HelpBot Assistant

How can I help you?

Column Rendering in Angular Grid Component

19 Mar 202624 minutes to read

Columns in the Syncfusion® Angular Grid define the structure and presentation of data. This section outlines manual, automatic, and dynamic rendering approaches to ensure clarity and flexibility in grid design.

The column definitions serve as the data source schema in the grid. Grid operations such as sorting, filtering, and grouping are performed based on column definitions. The field property of the grid column is necessary to map the data source values to the grid columns.

  1. If the column field is not specified in the dataSource, the column values will be empty.
  2. If the field name contains a dot operator, it is considered complex binding.
  3. The field property must be defined for a Template column to perform CRUD or data operations such as filtering and searching.

Define columns manually

To define columns manually in the grid, use the e-columns element to define the columns and represent each column with its respective properties such as field, headerText, type, and width set accordingly. This allows customization of the column’s behavior and appearance based on requirements.

Here’s an example code snippet that demonstrates defining columns manually in the Syncfusion® Angular Grid:

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

@Component({
    imports: [ GridModule ],
    providers: [PageService, SortService, FilterService, GroupService ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid [dataSource]='data' height='340'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
                    <e-column field='Freight' headerText='Freight' textAlign='Right' format='C2' width=90></e-column>
                    <e-column field='OrderDate' headerText='Order Date' textAlign='Right' format='yMd' width=120></e-column>
                </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

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

Auto-generated columns

Columns are automatically created when the columns option is not defined during Grid initialization. In this case, the Grid generates columns based on the fields in the dataSource. Each field in the data source is displayed as a column, and the field name appears in the column header.

The following code snippet enables auto-generated columns in the Syncfusion® Grid:

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

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid [dataSource]='data' height='300px'>
               </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

    ngOnInit(): void {
        this.data = data;
    }
}
import { AppComponent } from './app.component';
import { bootstrapApplication } from '@angular/platform-browser';

bootstrapApplication(AppComponent).catch((err) => console.error(err));

  • When columns are auto-generated, the column type is determined from the first record of the dataSource.
  • Auto-generating columns for large datasets can affect performance. To improve efficiency, columns can be defined manually in the columns option during initialization. Alternatively, the column virtualization feature can be enabled by setting enableColumnVirtualization to true.

Set primary key for auto-generated columns in editing

Primary key configuration for auto-generated columns is necessary when editing is enabled in the Grid to uniquely identify each row for operations such as updating or deleting data. This can be achieved by setting the isPrimaryKey property to true for the column object through the dataBound event.

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

@Component({
    imports: [ GridModule],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' height='280px' allowPaging='true' [editSettings]='editSettings' (dataBound)="dataBound()">
               </ejs-grid>`,
    providers: [EditService, PageService]
})
export class AppComponent implements OnInit {

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

    ngOnInit(): void {
        this.data = data;
        this.editSettings = { allowEditing: true, allowAdding: true, allowDeleting: true };
    }
    dataBound() {
        (((this.grid as GridComponent).columns[0]) as Column).isPrimaryKey = true;
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

If the column field name is known, the getColumnByField method can be used to retrieve the column object. Then, the isPrimaryKey property can be set to true for that column, as demonstrated in the code snippet below:

onDataBound(event: any): void {
    const column: ColumnModel = this.grid.getColumnByField('OrderID');
    column.isPrimaryKey = true;
  }

Defining column properties for auto-generated columns

Auto-generated columns can be customized to meet specific requirements by modifying properties such as type, format, and width for auto-generated columns in Syncfusion® Grid, use the dataBound event of the Grid component. The event is triggered after data has been loaded into the Grid, ensuring that all columns are created and available. At this point, the necessary options for the auto-generated columns can be configured.

In the below example, width is set for the “OrderID” column, type is set for the “Order Date” column and format is set for the “Freight” and “Order Date” columns.

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

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' (dataBound)="dataBound()" height='330px'>
               </ejs-grid>`
})
export class AppComponent implements OnInit {
    public data?: object[];
    @ViewChild('grid') public grid?: GridComponent;

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

    dataBound() {
        const columns = (this.grid as GridComponent).columns as Column[];
        for (const col of columns) {
        if (col.field === 'OrderID') {
            col.width = 120;
        }
        if (col.field === 'OrderDate') {
            col.type = 'date';
            col.format = 'yMd';
        }
        if (col.field === 'Freight') {
            col.format = 'P2';
        }
        }

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

Dynamic column generation

The Syncfusion® Grid component allows dynamic generation of columns at runtime based on the provided data. This feature is useful when displaying data with varying columns depending on specific requirements or dynamic data sources.

Using ngFor directive

To create dynamically generated columns in the Syncfusion® Grid component using the ngFor directive, first define an array of column objects in the component.ts file. Each column object should include a field and headerText property, which will be used to bind the corresponding properties of the e-column component.

Here is an example of dynamically generating columns in the grid using the *ngFor directive:

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

@Component({
  imports: [ GridModule ],
  providers: [PageService,SortService, FilterService, GroupService],
  standalone: true,
  selector: 'app-root',
  template: `<ejs-grid #grid [dataSource]='data' height='330'>
    <e-columns>
    <e-column *ngFor="let column of columns" [field]="column.field" [headerText]="column.headerText"></e-column> 
    </e-columns>
    </ejs-grid>`
})
export class AppComponent implements OnInit {

  public data?: object[];
  public columns?: NgIterable<ColumnModel> | null | undefined;

  ngOnInit(): void {
    this.data = data;
    this.columns = [
      { field: 'OrderID', headerText: 'Order ID' },
      { field: 'CustomerID', headerText: 'Customer ID' },
      { field: 'Freight', headerText: 'Freight' },
      { field: 'ShipCountry', headerText: 'ShipCountry' }
    ];
  }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

The data source or columns can be changed dynamically in the Syncfusion® Grid by using the changeDataSource method. For more information, please refer to this section.

Using valueAccessor property

Dynamic column generation using value accessor allows access and manipulation of the display data values in a grid column. By using the valueAccessor property of a grid column, the display value of the column can be customized based on the data.

To use the valueAccessor property, define the column with the property and provide a function that will return the formatted value. The function receives two arguments:

  • field: represents the data field of the column.
  • data: represents the data record for the corresponding row.
  • column: represents the current column object.

In the provided code, the currencyFormatter function takes the Freight value of the data object, appends the “Euro” symbol to it, and returns the formatted string. The concatenateFields function concatenates the “ShipCity” and “ShipRegion” values of the data object and returns the combined string.

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

@Component({
    imports: [ GridModule],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=100></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
                        <e-column field='Freight' headerText='Freight' textAlign='Right'
                         [valueAccessor]='currencyFormatter' width=80></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=130 [valueAccessor]='concatenateFields' ></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public currencyFormatter = (field: string, valueAccessordata: object, column: object) => {
        return '€' + (valueAccessordata as any)["Freight"];
    }

    public concatenateFields = (field: string, valueAccessordata: object, column: object) => {
        return (valueAccessordata as any)[field] + ' - ' + (valueAccessordata as any)["ShipRegion"];
    }

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

The valueAccessor function can have performance implications on large datasets. To avoid this, enable row virtualization by setting enableVirtualization to true. This ensures that only visible rows are rendered, improving performance.

Display array type columns

Array of objects binding to a column in the Grid component can be achieved using the valueAccessor property. This allows combining multiple values from an array into a single, readable string for display.

For example, consider a column named “Name” that contains an array of two objects, “FirstName” and “LastName”. The valueAccessor property can be used to join these two objects and bind them to the column.

import { stringData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { GridModule } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=90></e-column>
                        <e-column field='Name' headerText='Full Name' [valueAccessor]= 'getConcatenatedNames' width=120></e-column>
                        <e-column field='Title' headerText='Title' width=150></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

    public getConcatenatedNames = (field: string, data: object) => {
        return (data as any)[field as string].map((s: { FirstName: string, LastName: string }) => {
            return s.LastName || s.FirstName;
        }).join(' ');
    }

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

Expression column

An expression column displays a calculated value based on other fields in the same row. This can be implemented using the valueAccessor property, which allows defining a custom function to compute the value dynamically.

For example, consider an expression column named “Calories Intake”. This column calculates the total calories for each row using values from the “Protein”, “Fat”, and “Carbohydrate” columns. The valueAccessor function can perform the necessary calculation, including formulas or other custom logic.

import { foodInformation } from './datasource';
import { Component, OnInit } from '@angular/core';
import { GridModule } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='FoodName' headerText='Food Name' width=150></e-column>
                        <e-column field='Protein' headerText='Protein' textAlign='Right' width=120></e-column>
                        <e-column field='Fat' headerText='Fat' textAlign='Right' width=80></e-column>
                        <e-column field='Carbohydrate' headerText='Carbohydrate' textAlign='Right' width=120></e-column>
                        <e-column headerText='Calories Intake' textAlign='Right' [valueAccessor]='totalCalories' width=150></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

    public totalCalories = (field: string, data: { Protein: number, Fat: number, Carbohydrate: number }, column: Object): number => {
        return data.Protein * 4 + data.Fat * 9 + data.Carbohydrate * 4;
    }

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

Display serial number

Serial number display in the Grid for every row can be achieved using the rowDataBound event. The rowDataBound event is triggered for each row in the Grid when the data is bound to the Grid. Inside the rowDataBound event handler, a serial number can be calculated using the current page number, page size, and the row’s index on that page. These values are available from the Grid’s pageSettings property:

  • pageSize: Number of rows shown per page.
  • currentPage: The current page number.
  • rowIndex: The index of the row within the current page.

Here is an example code snippet that demonstrates displaying serial numbers in a Syncfusion® Grid using the rowDataBound event:

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

@Component({
    imports: [GridModule],
    providers:[PageService],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' (rowDataBound)='rowDataBound($event)' [editSettings]='editSettings' allowPaging="true" [pageSettings]="pageSettings"  [height]='295'>
                <e-columns>
                    <e-column field='S.No' textAlign='Center' width=120></e-column>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=140></e-column>
                    <e-column field='Freight' headerText='Freight' textAlign='Right' format='C' width=120></e-column>
                    <e-column field='OrderDate' headerText='Order Date' textAlign='Right' format='yMd' width=140></e-column>
                </e-columns>
               </ejs-grid>`,
})
export class AppComponent implements OnInit {
    public data?: object[];
    public editSettings?: EditSettingsModel;
    public pageSettings?: PageSettingsModel;
    @ViewChild('grid')
    public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.editSettings = {
            allowEditing: true,
            allowAdding: true,
            allowDeleting: true,
        };
        this.pageSettings = { pageSize: 8 };
    }
    rowDataBound({row}: RowDataBoundEventArgs) {
        if(row){
            var rowIndex = parseInt(row.getAttribute('aria-rowIndex') as string);
            var currentPageNumber = (this.grid as GridComponent).pageSettings.currentPage;
            var pageSize = (this.grid as GridComponent).pageSettings.pageSize;
            var startIndex = ((currentPageNumber as number) - 1) * (pageSize as number);
            (row.querySelector('.e-rowcell') as Element).innerHTML = (
                startIndex + rowIndex
            ).toString();
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Complex data binding

The Syncfusion® Grid component supports complex data binding by using the dot (.) operator in the column.field. This feature is particularly useful when dealing with nested or complex data structures.

Using local data

When binding local data that contains nested objects, the dot (.) operator in the column’s field property allows access to specific properties within those nested objects.

In the below example, the nested “Employee” object’s “FirstName” and “LastName” properties are bound using the dot (.) operator.

import { complexData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { GridModule } from '@syncfusion/ej2-angular-grids';

@Component({
imports: [ GridModule],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=120></e-column>
                        <e-column field='Name.FirstName' headerText='First Name' width=120></e-column>
                        <e-column field='Name.LastName' headerText='Last Name' width=120></e-column>
                        <e-column field='Title' headerText='Title' width=150></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

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

Using remote data

To enable complex data binding in the Grid component using remote data, add the expand query to the Grid’s query property. This ensures that related or nested data is eagerly loaded from the server, allowing direct access to complex fields using dot (.) notation in the column definitions.

In the below example, the expand query loads the nested “Employee” object’s “City” property using the dot (.) operator.

import { Component, NgModule, OnInit } from '@angular/core';
import { GridModule } from '@syncfusion/ej2-angular-grids';
import { DataManager, ODataV4Adaptor, Query } from '@syncfusion/ej2-data';

@Component({
imports: [ GridModule ],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' allowPaging='true' [query]='query' [height]='315'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=100></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=120></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=130 ></e-column>
                        <e-column field='Employee.City' headerText='City' width=130  ></e-column>
                    </e-columns>
                </ejs-grid>`,
})
export class AppComponent implements OnInit {
    public data: DataManager = new DataManager({
        adaptor: new ODataV4Adaptor(),
        crossDomain: true,
        url: 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders/',
    });
    public query = new Query().expand('Employee');
    ngOnInit(): void { }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Complex data binding with list or array of objects

Complex data binding with lists or arrays of objects is supported in the Grid. This feature allows binding complex data with multiple levels of nested objects and arrays to the Grid.

The following example shows setting a complex field for a data source containing an array of objects:

import { complexData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { GridModule } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [ GridModule ],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=120></e-column>
                        <e-column field='Names.0.FirstName' headerText='First Name' width=120></e-column>
                        <e-column field='Names.0.LastName' headerText='Last Name' width=120></e-column>
                        <e-column field='Title' headerText='Title' width=150></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];

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

Setting a complex column as a foreign key column

The Grid component provides the ability to set complex columns as foreign key columns. This allows related data from a foreign data source to be displayed based on a nested field value.

The following example demonstrates setting the “Employee.EmployeeID” column as a foreign key column and displaying the “FirstName” column from the foreign data.

import { data, employeeData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { ForeignKeyService, GridModule } from '@syncfusion/ej2-angular-grids';

@Component({
    imports: [GridModule],
    providers: [ForeignKeyService],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid [dataSource]='data' [height]='315'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=100></e-column>
                        <e-column field='Employee.EmployeeID' headerText='Employee Name'
                         width=120 foreignKeyValue='FirstName' foreignKeyField='EmployeeID' [dataSource]='employeeData'></e-column>
                        <e-column field='Freight' headerText='Freight' textAlign='Right' width=80></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=130  ></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public employeeData?: object[];

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