Immutable mode in Angular Grid component

23 Sep 202318 minutes to read

The immutable mode optimizes the Grid re-rendering performance by using the object reference and deep compare concept. When performing the Grid actions, it will only re-render the modified or newly added rows and prevent the re-rendering of the unchanged rows.

To enable this feature, you have to set the enableImmutableMode property as true.

This feature uses the primary key value for data comparison. So, you need to provide the isPrimaryKey column.

import { Component, ViewChild, OnInit } from "@angular/core";
import { ButtonComponent } from "@syncfusion/ej2-angular-buttons";
import { GridComponent } from "@syncfusion/ej2-angular-grids";
import { data } from "./datasource";

@Component({
    selector: 'app-root',
    templateUrl: 'app.template.html'
})
export class AppComponent implements OnInit {
  public data?: Object[] = [];
  public pageSettings?: Object = { pageSize: 50 };
  public immutableStart?: number;
  public normalStart?: number;
  public primaryKey?: number = 0;
  @ViewChild("immutable")
  public immutablegrid?: GridComponent;
  @ViewChild("normal")
  public normalgrid?: GridComponent;
  @ViewChild("addtop")
  public addtop?: ButtonComponent;
  @ViewChild("addbottom")
  public addbottom?: ButtonComponent;
  @ViewChild("delete")
  public delete?: ButtonComponent;
  @ViewChild("reverse")
  public reverse?: ButtonComponent;
  @ViewChild("paging")
  public paging?: ButtonComponent;
  public immutableInit?: boolean = true;
  public init?: boolean = true;

  ngOnInit(): void {
    this.data = data;
  }

  immutableBeforeDataBound(args: any): void {
    this.immutableStart = new Date().getTime();
  }

  immutableDataBound(args: any): void {
    let val: number | string = this.immutableInit ? '' : new Date().getTime() - (this.immutableStart as number);
    (document.getElementById("immutableDelete") as any).innerHTML =
      "Immutable rendering Time: " + "<b>" + val + "</b>" + "<b>ms</b>";
    this.immutableStart = 0; this.immutableInit = false;
  }

  normalBeforeDataBound(args: any): void {
    this.normalStart = new Date().getTime();
  }

  normalDataBound(args: any): void {
    let val: number | string  = this.init ? '' : new Date().getTime() - (this.normalStart as number);
    (document.getElementById("normalDelete") as any).innerHTML =
      "Normal rendering Time: " + "<b>" + val + "</b>" + "<b>ms</b>";
    this.normalStart = 0; this.init = false;
  }

  addTopEvent(): void {
    let addedRecords: object[] = [
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Chai', 'ProductID': 'Sasquatch Ale', 'CustomerID': 'QUEDE', 'CustomerName': 'Yoshi Tannamuri' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Georg Pipps', 'ProductID': 'Valkoinen suklaa', 'CustomerID': 'RATTC', 'CustomerName': 'Martín Sommer' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Yoshi Tannamuri', 'ProductID': 'Gula Malacca', 'CustomerID': 'COMMI', 'CustomerName': 'Ann Devon' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Palle Ibsen', 'ProductID': 'Rogede sild', 'CustomerID': 'RATTC', 'CustomerName': 'Paula Wilson' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Francisco Chang', 'ProductID': 'Mascarpone Fabioli', 'CustomerID': 'ROMEY', 'CustomerName': 'Jose Pavarotti' }
    ];
    var aData = addedRecords.concat((this.immutablegrid as any).dataSource as object[]);
    (this.normalgrid as any).setProperties({ dataSource: aData });
    (this.immutablegrid as any).setProperties({ dataSource: aData });
  }

  addBottomEvent(): void {
    let addedRecords: object[] = [
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Chai', 'ProductID': 'Sasquatch Ale', 'CustomerID': 'QUEDE', 'CustomerName': 'Yoshi Tannamuri' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Georg Pipps', 'ProductID': 'Valkoinen suklaa', 'CustomerID': 'RATTC', 'CustomerName': 'Martín Sommer' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Yoshi Tannamuri', 'ProductID': 'Gula Malacca', 'CustomerID': 'COMMI', 'CustomerName': 'Ann Devon' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Palle Ibsen', 'ProductID': 'Rogede sild', 'CustomerID': 'RATTC', 'CustomerName': 'Paula Wilson' },
      { 'OrderID': ++(this.primaryKey as number), 'ProductName': 'Francisco Chang', 'ProductID': 'Mascarpone Fabioli', 'CustomerID': 'ROMEY', 'CustomerName': 'Jose Pavarotti' }
    ]
    let aData = addedRecords.concat((this.immutablegrid as any).dataSource as object[]);
    (this.normalgrid as any).setProperties({ dataSource: aData });
    (this.immutablegrid as any).setProperties({ dataSource: aData });
  }

  deleteEvent(): void {
    ((this.immutablegrid as any).dataSource as object[]).splice(0, 5);
    (this.normalgrid as any).setProperties({ dataSource: (this.immutablegrid as any).dataSource });
    (this.immutablegrid as any).setProperties({ dataSource: (this.immutablegrid as any).dataSource });
  }

  sortEvent(): void {
    let aData: object[] = ((this.immutablegrid as any).dataSource as object[]).reverse();
    (this.normalgrid as any).setProperties({ dataSource: aData });
    (this.immutablegrid as any).setProperties({ dataSource: aData });
  }

  pageEvent(): void {
    let totalPage: number = ((this.immutablegrid as any).dataSource as object[]).length / (this.immutablegrid as any).pageSettings.pageSize;
    let page: number = Math.floor(Math.random() * totalPage) + 1;
    (this.normalgrid as any).setProperties({ pageSettings: { currentPage: page } });
    (this.immutablegrid as any).setProperties({ pageSettings: { currentPage: page } });
  }
}
<table>
    <tbody>
        <tr>
            <td>
                <span id='immutableDelete'></span>
            </td>
        </tr>
        <tr>
            <td>
                <span id='normalDelete'></span>
            </td>
        </tr>
        <tr>
            <td>
                <div>
                    <button #addtop ejs-button class="e-control e-btn e-lib e-info" (click)="addTopEvent()">Add 5 rows
                        at top</button>
                    <button #addbottom ejs-button class="e-control e-btn e-lib e-info" (click)="addBottomEvent()">Add 5
                        rows at bottom</button>
                    <button #delete ejs-button class="e-control e-btn e-lib e-info" (click)="deleteEvent()">Delete 5
                        rows</button>
                    <button #reverse ejs-button class="e-control e-btn e-lib e-info" (click)="sortEvent()">Sort Order
                        ID</button>
                    <button #paging ejs-button class="e-control e-btn e-lib e-info"
                        (click)="pageEvent()">Paging</button>
                </div>
            </td>
        </tr>
        <tr>
            <td>
                <span><b>Immutable Grid</b></span>
                <ejs-grid #immutable [dataSource]='data' height='350' enableImmutableMode="true" allowPaging="true"
                    [pageSettings]="pageSettings" (beforeDataBound)="immutableBeforeDataBound($event)"
                    (dataBound)="immutableDataBound($event)">
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' isPrimaryKey="true" width='120'
                            textAlign='Right'></e-column>
                        <e-column field='ProductName' headerText='Product Name' width='160'></e-column>
                        <e-column field='ProductID' headerText='Product ID' width='120' textAlign='Right'>
                        </e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width='120'></e-column>
                        <e-column field='CustomerName' headerText='Customer Name' width='160'></e-column>
                    </e-columns>
                </ejs-grid>
            </td>
        </tr>
        <tr>
            <td>
                <span><b>Normal Grid</b></span>
                <ejs-grid #normal [dataSource]='data' height='350' allowPaging="true" [pageSettings]="pageSettings"
                    (beforeDataBound)="normalBeforeDataBound($event)" (dataBound)="normalDataBound($event)">
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' isPrimaryKey="true" width='120'
                            textAlign='Right'></e-column>
                        <e-column field='ProductName' headerText='Product Name' width='160'></e-column>
                        <e-column field='ProductID' headerText='Product ID' width='120' textAlign='Right'>
                        </e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width='120'></e-column>
                        <e-column field='CustomerName' headerText='Customer Name' width='160'></e-column>
                    </e-columns>
                </ejs-grid>
            </td>
        </tr>
    </tbody>
</table>
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { GridModule, PageService } from '@syncfusion/ej2-angular-grids';
import { AppComponent } from './app.component';

/**
 * Module
 */
@NgModule({
    imports: [
        BrowserModule,
        GridModule
    ],
    declarations: [AppComponent],
    bootstrap: [AppComponent],
    providers: [PageService]
})
export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { AppModule } from './app.module';

import 'zone.js';
enableProdMode();
platformBrowserDynamic().bootstrapModule(AppModule);

Limitations

The following features are not supported in the immutable mode:

  • Frozen rows and columns
  • Row Template
  • Detail Template
  • Hierarchy Grid
  • Column reorder
  • Virtual scroll
  • Infinite scroll
  • Grouping

See also