Such a use case of the <vaadin-grid>
element will make a bad UX. The headers of the grid are not designed to be clickable by default. Therefore they look inactive, so the user will not think of them as of clickable links or buttons.
As for the Vaadin Grid, please consider making the columns hidable by specifying the <col hidable>
attribute. This will enable user to toggle the displayed columns by selecting those in a nice drop-down menu on the right of the grid header. See the Hiding Columns section in the grid documentation for an example.
If you want to toggle between different contents with a single click, it would be better to use the elements specifically designed for that instead, for example, <paper-tabs>
.
Your use case was difficult to implement, because the requirements are not designed in the Vaadin Grid API as well. I had to apply some unpleasant workarounds in order to achieve it. Please use the solution for learning rather than blindly copying the code. The caveats are explained below.
How to bind for the grid header click event
First of all, in Vaadin Grid, the DOM contents are not dynamic. They are treated as an initial configuration, and they are not used directly as the grid contents. Therefore, you can not bind the header click in the template.
In my solution, we attach the event listener on the grid itself. After catching a click on the grid, we need to manually determine if the header was clicked and find the clicked column index. In order to do that, we:
Get the event target reference. The click happens somewhere in the local DOM of the grid. event.target
will return the grid instead of the actual event target if Polymer uses Shadow DOM (disabled by default). Use Polymer API to ensure to have the correct target regardless of Polymer settings:
var target: Element = (<any> window).Polymer.dom(event).rootTarget;
Check the click target and all the elements up in the DOM tree until the end (if Polymer is in Shadow DOM mode) or the grid itself (if Polymer uses Shady DOM, which is the default mode) to find the column header cell element. For this check, we use Polymer API to check the element class name. We set a custom class name for the first name column header in the ngAfterViewInit()
method.
- If the header cell element is found, stop the search and call
this.toggleLastNameVisible();
.
- If the header cell element is not found, then it’s not the first name grid header that was clicked. Do nothing.
Note that we want to react on click, but we have to listen for the "mouseup" event on the grid instead of the click event. The reason is that sometimes the grid re-renders its contents after a header click, which breaks the header cell element finding. Mouseup works here, because it is fired before the grid process clicks.
How to programmatically show and hide the columns
Now that we solved the header click binding problem, we have to display the selected column and hide the others. Once again, we can not just bind the <col [hidden]="showOrHide">
attribute in the template, as well as we can not use *ngIf
to remove the hidden columns. Because the grid DOM contents are not dynamic.
We had to get the grid element reference and use the grid API:
@ViewChild('grid') gridRef: any;
toggleLastNameVisible(visible?: boolean) {
this._isLastNameVisible = visible !== undefined ? visible : !this._isLastNameVisible;
var grid: any = this.gridRef.nativeElement;
// Assuming that the last name is the second column
grid.set('columns.1.hidden', !this._isLastNameVisible);
}
Note that the ref is added in the template: <vaadin-grid #grid ...>
You can learn more about the grid API by reading through the Vaadin Grid Documentation and the API Reference. Hope that helps to understand better how the grid works.