HelpBot Assistant

How can I help you?

State Management in Angular Grid Component

19 Mar 202624 minutes to read

State management in the Angular Grid component enables maintaining the grid’s state across browser refreshes and during navigation within the same browser session. This capability helps retain the grid’s configuration and data after a page reload.

Enable state persistence in the grid using the enablePersistence property. When this property is set to true, the grid automatically saves its state in the browser’s localStorage, preserving the state across page reloads.

<ejs-grid [dataSource]="data" [enablePersistence]="true"></ejs-grid>

The Grid stores state using the combination of the component name and component ID in storage. For example, if the component name is “grid” and the ID is “OrderDetails”, the state is stored as gridOrderDetails.

When enabling state persistence, the following grid settings will persist in the local storage.

Grid Settings Properties persist Ignored properties
pageSettings currentPage
pageCount
pageSize
pageSizes
totalRecordsCount
template
enableQueryString
groupSettings allowReordering
columns
disablePageWiseAggregates
enableLazyLoading
showDropArea
showGroupedColumn
showToggleButton
showUngroupButton
captionTemplate
columns allowEditing
allowFiltering
allowGrouping
allowReordering
allowResizing
allowSearching
allowSorting
autoFit
disableHtmlEncode
enableGroupByFormat
field
foreignKeyField
index
showColumnMenu
showInColumnChooser
sortDirection
type
uid
visible
width
clipMode
commands
customAttributes
dataSource
defaultValue
displayAsCheckBox
editeditemplate
editType
filter
filterBarTemplate
filterTemplate
foreignKeyValue
format
formatter
freeze
headerTemplate
headerText
headerTextAlign
headerValueAccessor
hideAtMedia
isFrozen
isIdentity
isPrimaryKey
lockColumn
maxWidth
minWidth
sortComparer
template
textAlign
validationRules
valueAccessor
sortSettings - -
filterSettings - -
searchSettings - -
selectedRowIndex - -

The grid will persist only the last selected row index.

Restore initial Grid state

In the Syncfusion® Angular Grid component, restoring the grid to its initial state reverts all changes. This is useful for returning the grid to original settings, removing applied filters, sorting, or column reordering.

The following steps describe the process of resetting the grid to its initial state, even when the enablePersistence property is enabled.

Changing component Id

Restoring the initial state of the grid can be achieved by changing the component ID. This causes the grid to be treated as a new instance, reverting to default settings.

import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { FilterService, GridComponent, GridModule, GroupService, PageService } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule,ButtonModule],
    standalone: true,
    selector: 'app-root',
    template: `<button ejs-button id='restore' (click)='clickHandler()'>Restore to initial state</button>
               <ejs-grid #grid [id]='gridId' [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' [allowFiltering]='true'
           height='210px'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
    providers: [GroupService, FilterService, PageService]
})
export class AppComponent implements OnInit {

    public data?: object[];
    @ViewChild('grid')
    public grid?: GridComponent;
    public gridId?: string = 'OrderDetails'; // id for the Grid component

    ngOnInit(): void {
        this.data = data;
    }
    clickHandler() {
        this.gridId = `OrderDetails` + Math.floor(Math.random() * 10);
        location.reload();
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Clearing local storage

Clearing the local storage associated with the grid component resets the grid by removing stored state information and returning the grid to its original configuration.

import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { FilterService, GridComponent, GridModule, GroupService, PageService } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [GridModule, ButtonModule],
    standalone: true,
    selector: 'app-root',
    template: `<button ejs-button id='restore' (click)='clickHandler()' cssClass='e-primary'>Restore to initial state</button>
               <ejs-grid #grid id="OrderDetails" [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' [allowFiltering]='true'
           height='210px'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
    providers: [GroupService, FilterService, PageService]
})
export class AppComponent implements OnInit {

    public data?: object[];
    @ViewChild('grid')
    public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
    }
    clickHandler() {
        const grid = this.grid as GridComponent;
        grid.enablePersistence = false;
        window.localStorage.setItem("gridOrderDetails", ""); // Here grid is component name and OrderDetails is component ID
        grid.destroy();
        location.reload();
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Restore to specific state version

Syncfusion® Angular Grid supports version-based persistence for restoration to a specific state.

Steps to enable version-based persistence in the Angular Grid:

  1. Import enableVersionBasedPersistence from @syncfusion/ej2-base.
  2. Call enableVersionBasedPersistence(true) to turn on version-based persistence for the application.
  3. Define the grid with the required properties and bind the data source.
  4. Set the enablePersistence property on the grid to store and restore its state automatically.
  5. Use the ej2state-persistenceVersion property on the grid to define the version of the persisted state.

The example below assigns the targeted version to the grid’s ej2statepersistenceVersion dynamically in a clickHandler method. The code checks local storage for a persisted state for the selected version; if found, the grid is updated with settings retrieved from local storage (columns, filterSettings, groupSettings, sortSettings, pageSettings, and selectedRowIndex). If no persisted state is found, the current grid state is saved to local storage using the getPersistData method.

The example below demonstrates integration of version-based persistence and restoration to a specific state version:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { GridModule,FilterService, PageService, GridComponent, GroupService, SortService, ReorderService } from '@syncfusion/ej2-angular-grids';
import { enableVersionBasedPersistence } from '@syncfusion/ej2-base';

enableVersionBasedPersistence(true);

@Component({
    imports: [ GridModule,ButtonModule],
    standalone: true,
    selector: 'app-root',
    template: `<h4 id='message'>{{message}}</h4>
    <button ejs-button *ngFor="let v of versions" [id]="'restore' + v" (click)="clickHandler('v.' + v)">Version {{ v }}</button>
               <ejs-grid #grid id="OrderDetails" [dataSource]='data' [enablePersistence]='true' [ej2StatePersistenceVersion]='gridversion' 
               [allowPaging]='true' [allowFiltering]='true' [allowReordering]='true' [allowSorting]='true' [allowGrouping]='true' height='160px'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
    providers: [FilterService, PageService, GroupService, SortService, ReorderService]
})
export class AppComponent implements OnInit {

    public data?: object[];
    @ViewChild('grid')
    public grid?: GridComponent;
    public message?: string;
    public gridversion?: string = 'v.0';
    public versions: number[] = [1, 2, 3];


    ngOnInit(): void {
        this.data = data;
    }
    clickHandler(version: string) {
        const grid = this.grid as GridComponent;
        grid.ej2StatePersistenceVersion = version;
        var persistedGridSettings: string = (window.localStorage.getItem(`gridOrderDetails` + grid.ej2StatePersistenceVersion)) as string;
        if (persistedGridSettings) {
            grid.setProperties(JSON.parse(persistedGridSettings));
            this.message = `Grid state restored to ` + version;
        } else {
            var gridData = grid.getPersistData();
            window.localStorage.setItem((`gridOrderDetails` + grid.ej2StatePersistenceVersion), gridData);
        }

    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Restore to previous state

The Syncfusion® Angular Grid component supports saving and restoring state using local storage. This feature preserves the current state of the grid, such as column order, sorting, and filtering, enabling a return to previous configurations.

Implement this functionality using the getItem and setItem methods for local storage, along with the Grid component’s setProperties and getPersistData methods.

The code below demonstrates saving and restoring the previous state of a Syncfusion® Angular Grid component using local storage.

import { data } from './datasource';
import { Component, ViewChild } from '@angular/core';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { EditService, FilterService, GridComponent, GridModule, GroupService, SortService, ToolbarService } from '@syncfusion/ej2-angular-grids';

@Component({
  imports: [GridModule,ButtonModule],
  standalone: true,
  selector: "app-root",
  templateUrl: "app.component.html",
  providers: [GroupService, ToolbarService, SortService, EditService, FilterService],
})
export class AppComponent {
  public data?: Object[];
  public groupOptions?: Object;
  public pageSettings?: Object;
  public editSettings?: Object;
  public filterOptions?: Object;
  public toolbar?: string[];
  public orderidrules?: Object;
  public customeridrules?: Object;
  public freightrules?: Object;
  public editparams?: Object;
  public formatoptions?: Object;
  @ViewChild("Orders")
  public grid?: GridComponent;
  public state?: GridComponent;
  public message?: string;

  ngOnInit(): void {
    this.data = data;
    this.groupOptions = { showGroupedColumn: false, columns: ["ShipCountry"] };
    this.filterOptions = { type: "Menu" };
    this.pageSettings = { pageCount: 5 };
    this.editSettings = { allowEditing: true };
    this.toolbar = ["Edit", "Update", "Cancel"];
    this.orderidrules = { required: true, number: true };
    this.customeridrules = { required: true };
    this.freightrules = { required: true };
    this.editparams = { params: { popupHeight: "300px" } };
    this.formatoptions = { type: "dateTime", format: "M/d/y hh:mm a" };
  }
  actionBegin() {
    this.message = "";
  }
  // Save grid state to local storage
  save() {
    var persistData = (this.grid as GridComponent).getPersistData(); // Grid persistData
    window.localStorage.setItem("gridOrders", persistData);
    this.message = "Grid state saved.";
  }
  // Restore grid state from local storage
  restore() {
    let value: string = window.localStorage.getItem("gridOrders") as string; //"gridOrders" is component name + component id.
    this.state = JSON.parse(value);
    if (this.state) {
      (this.grid as GridComponent).setProperties(this.state);
      this.message = "Previous grid state restored.";
    } else {
      this.message = "No saved state found.";
    }
  }
}
<div class="control-section">
    <button ejs-button class="e-success" (click)="save()">Save</button>
    <button ejs-button class="e-danger" (click)="restore()">restore</button>
    <div id='message'>{{message}}</div>
    <ejs-grid #Orders id="Orders" [dataSource]="data" allowPaging="true" allowSorting="true" allowFiltering="true"
        [allowGrouping]="true" [editSettings]="editSettings" [groupSettings]="groupOptions"
        [filterSettings]="filterOptions" [toolbar]="toolbar" [pageSettings]="pageSettings" [enablePersistence]="true"
        height="200" (actionBegin)="actionBegin()">
        <e-columns>
            <e-column field="OrderID" headerText="Order ID" width="140" textAlign="Right" isPrimaryKey="true"
                [validationRules]="orderidrules"></e-column>
            <e-column field="CustomerID" headerText="Customer ID" width="140" [validationRules]="customeridrules">
            </e-column>
            <e-column field="Freight" headerText="Freight" width="140" format="C2" textAlign="Right"
                editType="numericedit" [validationRules]="freightrules"></e-column>
            <e-column field="OrderDate" [allowGrouping]="false" headerText="Order Date" width="120"
                editType="datetimepickeredit" [format]="formatoptions" textAlign="Right"></e-column>
            <e-column field="ShipCountry" headerText="Ship Country" width="150" editType="dropdownedit"
                [edit]="editparams"></e-column>
        </e-columns>
    </ejs-grid>
</div>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Maintaining custom query in a persistent state

When enablePersistence is enabled, the grid does not automatically maintain custom query parameters after a page load because the grid refreshes its query params on every load. Maintain custom query params by resetting the addParams method in the actionBegin event.

import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { FilterService, GridComponent, GridModule, GroupService, PageService } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule ],
    providers: [GroupService, FilterService, PageService],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #Orders [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' [allowFiltering]='true'
           height='210px' (actionBegin)='actionBegin()'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='EmployeeID' headerText='Employee ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
})
export class AppComponent implements OnInit {

    public data?: object[];
    @ViewChild('Orders')
    public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
    }
    actionBegin() {
        (this.grid as GridComponent).query.addParams('dataSource', 'data');
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Observables binding with state persistence

The Syncfusion Angular Grid supports state persistence when using The Syncfusion Angular Grid supports state persistence with observable binding, ensuring the grid retains state across sessions. This is useful for real-time data updates or asynchronous data sources while preserving interactions such as sorting, filtering, paging, and grouping.

Implementing state persistence with observables requires manual handling of the initial query state. This involves:

  • Retrieving the initial query using the grid’s getDataModule method with generateQuery.
  • Obtaining the state from the query via getStateEventArgument method.
  • Sending the retrieved state to the service to fetch data accordingly.

Except for the initial render, state persistence retains manually performed actions by storing the state in the browser’s localStorage, allowing persistence across page reloads.

The following example demonstrates using the created event to send the persisted state to the service at initial render:

import { OrdersService } from './order.service';
import { AsyncPipe } from '@angular/common';
import { Component, ViewChild } from '@angular/core';
import { DataStateChangeEventArgs, FilterService, GridComponent, GridModule, GroupService, PageService, SortService } from '@syncfusion/ej2-angular-grids';
import { getStateEventArgument } from '@syncfusion/ej2-grids';
import { Observable } from 'rxjs';

@Component({
    imports: [ GridModule, AsyncPipe],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #persistGrid height="170" id="persistGrid" [dataSource]="data | async" [enablePersistence]="true" allowPaging="true" [pageSettings]="pageSettings" allowSorting="true" [sortSettings]="sortSettings" allowFiltering="true" [filterSettings]="filterSettings" allowGrouping="true" [groupSettings]="groupSettings" (created)="created()" (dataStateChange)="dataStateChange($event)">
                  <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120 ></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150 ></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150 ></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150 ></e-column>
                  </e-columns>
                </ejs-grid>`,
        providers: [GroupService, SortService, FilterService, PageService]
    })
export class AppComponent {
    @ViewChild('persistGrid', { static: true }) grid!: GridComponent;
    public data: Observable<DataStateChangeEventArgs>;
    public pageSettings = { pageSize: 12, currentPage: 2 };
    public sortSettings = {
      columns: [{ field: 'OrderID', direction: 'Descending' }],
    };
    public filterSettings = {
      columns: [{field: 'CustomerID', matchCase: false, operator: 'startswith', predicate: 'and', value: 'A' }],
    };
    public groupSettings = { columns: ['ShipCity'] };
    constructor(private service: OrdersService) {
      this.data = service;
    }
    public created(): void {
      const queries = this.grid.getDataModule().generateQuery(); // Generate the initial query state from the Grid's data module.
      const state = getStateEventArgument(queries); // Retrieve the Grid's current state based on the generated query.
      this.service.execute(state); // Send the retrieved state to the service to fetch data accordingly.
    }
    public dataStateChange(state: DataStateChangeEventArgs): void {
      this.service.execute(state);
    }
}
import { Injectable } from '@angular/core';
import { DataStateChangeEventArgs, Sorts } from '@syncfusion/ej2-angular-grids';
import { Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class OrdersService extends Subject<DataStateChangeEventArgs> {
  private BASE_URL ='https://services.odata.org/V4/Northwind/Northwind.svc/Orders';
  constructor() {
    super();
  }
  public execute(state: any): void {
    this.getData(state).subscribe((x) => super.next(x));
  }
  protected getData(state: DataStateChangeEventArgs): Observable<DataStateChangeEventArgs> {
    const pageQuery = `$skip=${state.skip}&$top=${state.take}`;
    let sortQuery: string = '';
    let filterQuery = '';
     if (state.sorted && state.sorted.length) {
      const sorts = state.sorted as Sorts[];

      const orderby = sorts
        .map((obj) => {
          const direction = (obj.direction ?? 'Ascending').toLowerCase();
          return direction === 'descending' ? `${obj.name} desc` : obj.name;
        })
        .reverse()
        .join(',');

      sortQuery = `&$orderby=${orderby}`;
    }
    if (state.where) {
      filterQuery =
        `&$filter=` +
        state.where.map((obj) => {
          return obj.predicates
            .map((predicate) => {
              return predicate.operator === 'equal'
                ? `${predicate.field} eq ${predicate.value}`
                : `${predicate.operator}(tolower(${predicate.field}),'${predicate.value}')`;
            })
            .reverse()
            .join(' and ');
        });
    }
    return this.fetchData(
      `${this.BASE_URL}?${pageQuery}${sortQuery}${filterQuery}&$count=true`
    ).pipe(
      map((response: any) => {
        const result = response['value'];
        const count = response['@odata.count'];
        return { result, count } as DataStateChangeEventArgs;
      })
    );
  }
  private fetchData(url: string): Observable<any> {
    return new Observable((observer) => {
      fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          return response.json();
        })
        .then((data) => {
          observer.next(data);
          observer.complete();
        })
        .catch((error) => {
          observer.error(error);
        });
    });
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Get or set local storage value

If the enablePersistence property is set to true, the grid property value is saved in window.localStorage for reference. Get or set the localStorage value using the getItem and setItem methods in window.localStorage.

Retrieve the grid model from Local Storage as follows:

//get the Grid model.
let value: string = window.localStorage.getItem('gridOrders'); //"gridOrders" is component name + component id.
let model: Object = JSON.parse(value);
//set the Grid model.
window.localStorage.setItem('gridOrders', JSON.stringify(value)); //"gridOrders" is component name + component id.

Prevent columns from persisting

In the Syncfusion® Angular Grid component, certain settings may need to be excluded from being saved when the enablePersistence feature is turned on. When the enablePersistence property is true, grid properties such as Grouping, Paging, Filtering, Sorting, and Columns persist. To prevent specific properties from being persisted, the addOnPersist method can be used.

The following example demonstrates preventing grid columns from persisting. Override the addOnPersist method in the dataBound event and remove the columns from the key list given for persistence.

import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { ButtonAllModule } from '@syncfusion/ej2-angular-buttons';
import { Column, FilterService, GridComponent, GridModule, GroupService, PageService } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule, ButtonAllModule ],
    standalone: true,
    selector: 'app-root',
    template: `<button ejs-button id='add' (click)='addColumn()'>Add Columns</button>
               <button ejs-button id='remove' (click)='removeColumn()'>Remove Columns</button>
               <ejs-grid #grid id="Orders" [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' height='210px' (dataBound)='dataBound()'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
    providers: [GroupService, FilterService, PageService]
})
export class AppComponent implements OnInit {
    public data?: object[];
    @ViewChild('grid')
    public grid?: GridComponent;
    ngOnInit(): void {
        this.data = data;
    }
    dataBound() {
        let cloned = (this.grid as any).addOnPersist;
        (this.grid as any).addOnPersist = function (key: any) {
            key = key.filter((item: string)  => item !== "columns");
            return cloned.call(this, key);
        };
    }

    addColumn() {
        let obj = { field: "Freight", headerText: 'Freight', width: 120 };
        ((this.grid as GridComponent).columns as Column[]).push(obj as Column); //you can add the columns by using the Grid columns method
        (this.grid as GridComponent).refreshColumns();
   }

    removeColumn() {
        (this.grid as GridComponent).columns.pop();
        (this.grid as GridComponent).refreshColumns();
   }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Add to persist

Persistence can be added to a Syncfusion® Angular Grid component to enhance the application experience. Persistence allows saving and restoring the state of the grid, including column layouts, sorting, filtering, and other settings. This section describes the process of persisting column templates, header templates, and header text settings in the Angular Grid.

Add a new column in persisted columns list

When the enablePersistence property is set to true in the Syncfusion® Angular Grid component, column configurations are automatically persisted. To add new columns to an already persisted state, the grid’s built-in methods such as push can be used, followed by calling the refreshColumns method to update the UI with the newly added columns.

import { data } from './datasource';
import { Component, OnInit, ViewChild } from '@angular/core';
import { Column, FilterService, GridComponent, GridModule, GroupService, PageService } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<button ejs-button id='add' (click)='addColumn()'>Add Columns</button>
               <ejs-grid #grid id="Orders" [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' height='210px'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                </e-columns>
                </ejs-grid>`,
    providers: [GroupService, FilterService, PageService]
})
export class AppComponent implements OnInit {
    public data?: object[];
    @ViewChild('grid')
    public grid?: GridComponent;
    ngOnInit(): void {
        this.data = data;
    }
    addColumn() {
        let obj = { field: "Freight", headerText: 'Freight', width: 120 };
        ((this.grid as GridComponent).columns as Column[]).push(obj as Column); //you can add the columns by using the Grid columns method
        (this.grid as GridComponent).refreshColumns();
   }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Adding new columns using ColumnDirectives directly in the grid initialization is not recommended when intending to persist new columns with the existing columns list.

Persist the column template, header template and header text

By default, when the enablePersistence property is true in the Syncfusion® Angular Grid component, certain column properties such as column template, header text, header template, column formatter, and value accessor are not persisted because these properties can be customized at the application level.

Restoring these column properties and achieving persistence requires cloning the grid’s columns property using JavaScript Object’s assign method and manually storing it along with the persist data. When restoring the settings, assign this cloned column object to the grid’s columns property to restore the column settings. The sample below demonstrates this process:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, GroupService } from '@syncfusion/ej2-angular-grids'
import { ButtonAllModule } from '@syncfusion/ej2-angular-buttons'

import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { FilterService, PageService, GridComponent, Column } from '@syncfusion/ej2-angular-grids';

@Component({
imports: [ GridModule, ButtonAllModule],
providers: [GroupService, FilterService, PageService]
standalone: true,
    selector: 'app-root',
    template: `<div id='message'>{{message}}</div><button ejs-button id='save' (click)='save()'>Save column settings</button><button ejs-button id='restore' (click)='restore()'>Restore column settings</button>
               <ejs-grid #Grid id="Orders" [dataSource]='data' [enablePersistence]='true' [allowPaging]='true' [allowFiltering]='true'
           height='210px'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120>
                    </e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=150 headerTemplate='<button ejs-button>HeaderTemplate</button>'>
                    </e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=150 template='#template'>
                    </e-column>
                </e-columns>
                </ejs-grid>`,
    
})
export class AppComponent implements OnInit {

    public data?: object[];
    @ViewChild('Grid')
    public grid?: GridComponent;
    public message: string = '';
    public persistedGridSettings?: object;

    ngOnInit(): void {
        this.data = data;
    }
    save() {
        this.persistedGridSettings = JSON.parse(((this.grid as GridComponent)).getPersistData());
        var gridColumns = Object.assign([], ((this.grid as GridComponent)).getColumns());
        (this.persistedGridSettings as any).columns.forEach((persistedColumn: Column) => {
            const column = gridColumns.find((col: Column) => col.field === persistedColumn.field);
            if (column) {
                persistedColumn.headerText = 'Text Changed';
                persistedColumn.template = (column as Column).template;
                persistedColumn.headerTemplate = (column as Column).headerTemplate;
            }
        });
        window.localStorage.setItem('gridOrders1', JSON.stringify(this.persistedGridSettings));
        this.grid?.setProperties(this.persistedGridSettings as object);
        this.message = 'Saved the headerText, template column, and headerTemplate properties in the persisted settings';
    }
    restore() {
        const savedSettings = window.localStorage.getItem("gridOrders1");
        if (savedSettings) {
            this.grid?.setProperties(JSON.parse(savedSettings));
            this.message = 'Restored the headerText, template column, and headerTemplate';
        } else {
            this.message = 'No saved settings found.';
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));