It is listed as a limitation that the columns state doesn't allow functions and so to handle those in the initColumns but I have several templates for the column content so that doesn't seem very practical. Additionally if you store the entire column state then as far as I can tell if I add new columns in future any users with state stored won't pick up those new columns. So rather than restore the entire state of columns I just want to apply the things the user can actual change - visibility, pinning and order. Is there a way to get the existing columns definition to merge with the state first or to apply those parts programatically? I can see you can set pinning through api functions so I could read the state and call functions myself but I can't see how to hide or move columns through api. Is there anyway to achieve this?
Hi Katy,
The hidden property of the IgxColumnComponent is used to control hiding/showing of a column. For column moving, you are expected to use the moveColumn method exposed on the IgxGrid.
You can get the existing columns by reading the columns property of the grid:
const columns = this.grid.columns; columns[1].hidden = true; this.grid.moveColumn(columns[1], columns[3]
Thanks
I have it working now. However, it is a bit inefficient to have to reorder the columns using the moveColumn method to get them back into desired order when you know that order up front. This might take several moves. I assume there is no way to set the order in one go though?
The problem is the limitation already mentioned:
getState method uses JSON.stringify() method to convert the original objects to a JSON string. However, this does not support Functions, thats why the [IgxGridState] directive will ignore the columns formatter, filters, summaries, sortStrategy, cellClasses and cellStyles properties. It is up to the developer to keep track and restore those on application level. It is recommended to set these in the onColumnInit event:
getState
IgxGridState
formatter
filters
summaries
sortStrategy
cellClasses
cellStyles
onColumnInit
I already have all the logic for columns in the html. So I don't want to have to rewrite all that into a onColumnInit event instead. So that is why I was trying to reinstate the things the user can change only so that I don't lose all that other information when restoring the state
e.g for one of my columns I have
I understand. Restoring the columns will restore all state, except for the properties mentioned in the limitation. In this situation, you should implement logic in the onColumnInit event, where to restore other things such as the column templates. The two approaches are not in a conflict, but the logic in the onColumnInit event should complement everything done by the directive itself.
Let's say that the igxStateDirective will restore the column `personId` with its filtering, sorting state, hidden state. etc, but it will not restore its template. In this case, the onColumnInit event should have the following code to supplement the state directive:
public onColumnInit(column: IgxColumnComponent) { if (column.field === 'personId') { column.bodyTemplate = this.personIdTemplate; } }
Hristo
The trouble with this approach is I have multiple grids. They use various templates already for the columns, cell edit templates, styles, etc. I have created a standard directive for adding in the state saving which I want to then include into all the grids across the application. The approach taken means I would need to go back through all the grids and add the logic to reinstate the templates, cell templates, styles etc in the onColumnInit. It would also be very easy in future for someone to add things into the html that are then dropped if state is reinstated without realizing they needed handling in the onColumnInit also.
So I would rather avoid dropping those when restoring state. Also if new columns are added later then the user won't be getting them if we just restore the columns they had saved previously.
Considering most of the examples show having templates in the html for configuring the grid columns and so I would assume that is a normal approach a lot of people would take, it seems a really big limitation to me to then drop all of those and expect to reinstate in the onColumnInit.
I will try some other ways to see if I can avoid dropping them as part of reinstating the state.
See this sample that I have prepared for you.
What it does is it extends the IgxGridState directive and subscribes to the onColumnInit event for the corresponding grid. This way, you save the burden of having to subcsribe to each of the many grids you have, rather than that - you do it once in the directive, and this directive is applied to each grid (as it is now, right ?)
In short, here is the summarized thing to do:
export class IgxGridStateExtendedDirective extends IgxGridStateDirective { public template: TemplateRef<any>; constructor( @Host() @Optional() protected currGrid: IgxGridComponent) { currGrid.onColumnInit.subscribe((column: IgxColumnComponent) => { onColumnInit(column, this.template); }); } } export function onColumnInit(column: IgxColumnComponent, template: any) { if (column.field === 'IsActive') { column.bodyTemplate = template; } } export class GridSaveStateComponent implements OnInit, AfterViewInit { public restoreGridState() { this.state.template = this.isActiveTemplate; ... } }
There are few more things to do, see them in the example. In short, from the component that holds your grid, you need to pass the templates/functions to the state directive, as it is done in the restoreGridState method. My example does it for one template, but you can do it for anything.
Please review it and let me know if you have any questions.
I figured out the issue. In my template I was using a *ngIf and I guess the redrawing of that was causing the onColumnChange to get triggered again during the same time that the state was being applied and then overriding the changes. I changed it to a [hidden] instead and now it all is working well.
I have taken a slightly different approach where I first capture all the templates/cell styles etc from the original columns and then I use that to reinstate them in the onColumnsInit in the directive so that I don't have to pass the templates in.
This is all working well now. Thanks for your help.
I am glad you have found the issue.
And yes - setting templates and other stuff initially in the onColumnsInit event will save you doing what I suggested doing though the directive. Nice work !