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?
Actually I have a further issue that I can't seem to reset the state. Is there a way to clear any moves so it goes back to original order?
There is a better way to recreate the columns order, but again, it will work like the state directive itself - will restore much more column properties, than just what you need. See the implementation in the state.directive.ts file.
Is it rallly an issue for you if some other properties get restored too? Please provide some more details on your scenario (like what properties you don`t want to be restored) so I can suggest a better solution.
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
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 !
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.
If you have changed the grid.columnList collection by yourself (as I have suggested initially), this will be trigerirng the onColumnInit event. Considering my last suggestion with the extended directive, you will not need to touch the columnList anymore.
Please let me know if this resolves the issue on your end, before we continue. If it does not, you can modify my sample to reproduce what;s happening.
Actually now I am having issues with using the column state at all. Without it it is restoring the filtering and sorting state ok. But when I include it I can see that the column state is being restored and then its calling the on column init as expected. Then the filtering etc is restored and the state all looks good. But then something is triggering another onColumnChanged and that is then losing the state and restoring it back to the original. It works fine in your example so I am not too sure what I have done differently. Is there any way to tell what triggers the onColumnChanged method? I am debugging it but not able to trace what is triggering it exactly.
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.