Tree Column in Angular TreeGrid component

19 Sep 202424 minutes to read

The Syncfusion Angular TreeGrid component provides a convenient way to represent parent-child relationships using expand and collapse icons in the tree column cell. This can be achieved by utilizing the treeColumnIndex property by setting its value to a column index. This guide outlines how to configure and use this property to display the expand or collapse icon in the desired column.

<ejs-treegrid [dataSource]='data' [treeColumnIndex]='2'>
    <!-- Other tree grid configurations -->
</ejs-treegrid>

Change expand and collapse icon

The Syncfusion Angular TreeGrid component allows to customize the default expand and collapse icons by applying custom CSS styles.

To customize the expand and collapse icons, use the following CSS styles:

.e-treegrid .e-treegridexpand::before {
  content: "\2795";
}

.e-treegrid .e-treegridcollapse::before {
  content: "\2796";
}

In the following demo, the expand and collapse icons are customized using the CSS styles

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { sampleData } from './datasource';

@Component({
    imports: [TreeGridModule,],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    encapsulation: ViewEncapsulation.None,
    selector: 'app-container',
    template: ` <ejs-treegrid #treegrid [dataSource]='data' height='285' [treeColumnIndex]='1' childMapping='subtasks' >
                    <e-columns>
                        <e-column field='taskID' headerText='Task ID' textAlign='Right' width=90></e-column>
                        <e-column field='taskName' headerText='Task Name' textAlign='Left' width=180></e-column>
                        <e-column field='startDate' headerText='Start Date' textAlign='Right' format='yMd' width=90></e-column>
                        <e-column field='duration' headerText='Duration' textAlign='Right' width=80></e-column>
                    </e-columns>
                </ejs-treegrid>`,
    styleUrls: ['./custom-column.style.css']
})
export class AppComponent implements OnInit {

    public data?: Object[];

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

.e-treegrid .e-treegridcollapse::before {
  content: '\2796';
}

Change indent space of tree column cell text

The TreeGrid component allows to customize the indent space of tree column cell text by leveraging the queryCellInfo event.

In the following demonstration, apply an indent space by adding a CSS class to the tree column cell using the queryCellInfo event.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { sampleData } from './datasource';
import { TreeGridComponent, Column } from '@syncfusion/ej2-angular-treegrid';
import { ChangeEventArgs } from '@syncfusion/ej2-angular-dropdowns';

@Component({
    imports: [TreeGridModule],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    selector: 'app-container',
    encapsulation: ViewEncapsulation.None,
    template: `<ejs-treegrid #treegrid [dataSource]='data' height='250' [treeColumnIndex]='1' childMapping='subtasks' (queryCellInfo)=querycellinfo($event)>
                <e-columns>
                  <e-column field='taskID' headerText='Task ID' width=90></e-column>
                  <e-column field='taskName' headerText='Task Name' width=180></e-column>
                  <e-column field='startDate' headerText='Start Date' format='yMd' width=90></e-column>
                  <e-column field='duration' headerText='Duration' width=80></e-column>
                </e-columns>
              </ejs-treegrid>`,
    styles: [
        ` 
          .indents {
            text-indent: 20px !important;
          }
      `],
})
export class AppComponent implements OnInit {
    public data?: object[];
    @ViewChild('treegrid') public treegrid?: TreeGridComponent;

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

    querycellinfo(args: any): void {
        if (
            !args.data.hasChildRecords &&
            args.column.index == (this.treegrid as TreeGridComponent).treeColumnIndex
        ) {
            args.cell.classList.add('indents');
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Render parent rows in collapsed state

You can easily render all the parent rows in a collapsed state in the TreeGrid component using the enableCollapseAll property. Using this property, all parent rows are collapsed during the initial rendering.

In the following demo, all parent rows are rendered in a collapsed state in initial rendering.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit, } from '@angular/core';
import { sampleData } from './datasource';

@Component({
    imports: [TreeGridModule,],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-treegrid #treegrid [dataSource]='data' height='285' [treeColumnIndex]='1' childMapping='subtasks' [enableCollapseAll]=true>
                 <e-columns>
                    <e-column field='taskID' headerText='Task ID' textAlign='Right' width=90></e-column>
                    <e-column field='taskName' headerText='Task Name' textAlign='Left' width=180></e-column>
                    <e-column field='startDate' headerText='Start Date' textAlign='Right' format='yMd' width=90></e-column>
                    <e-column field='duration' headerText='Duration' textAlign='Right' width=80></e-column>
                 </e-columns>
               </ejs-treegrid>`,

})
export class AppComponent implements OnInit {

    public data?: Object[];

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

Retain expanded and collapsed state

To maintain the expanded and collapsed state of specific parent rows during initial rendering in the
Tree Grid, you can utilize the expandStateMapping property. This property corresponds to a value within the data object of the data source, signifying the expand/collapse status of the parent row.

In the following demonstration, the JSON object has an isExpanded property with a boolean value. Based on this value, the parent rows are shown in an expanded or collapsed state.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit } from '@angular/core';
import { expandData } from './datasource';

@Component({
    imports: [TreeGridModule, ],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-treegrid #treegrid [dataSource]='data' height='250' [treeColumnIndex]='1' childMapping='subtasks' expandStateMapping="isExpanded" >
                  <e-columns>
                    <e-column field="taskID" headerText="Task ID" width="70" textAlign="Right"></e-column>
                    <e-column field="taskName" headerText="Task Name" width="200"></e-column>
                    <e-column field="startDate" headerText="Start Date" width="90" format="yMd" textAlign="Right"></e-column>
                    <e-column field="endDate" headerText="End Date" width="90" format="yMd" textAlign="Right"></e-column>
                    <e-column field="duration" headerText="Duration" width="80" textAlign="Right"></e-column>
                    <e-column field="progress" headerText="Progress" width="80" ></e-column>
                    <e-column field="priority" headerText="Priority" width="90"></e-column>   
                  </e-columns>
                </ejs-treegrid>`
})
export class AppComponent implements OnInit {

    public data?: Object[];

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

export let expandData = [
    {
      taskID: 1,
      taskName: 'Planning',
      startDate: new Date('02/03/2017'),
      endDate: new Date('02/07/2017'),
      progress: 100,
      duration: 5,
      isExpanded: true,
      priority: 'Normal',
      approved: false,
      subtasks: [
        {
          taskID: 2,
          taskName: 'Plan timeline',
          startDate: new Date('02/03/2017'),
          endDate: new Date('02/07/2017'),
          duration: 10,
          progress: 100,
          priority: 'Normal',
          isExpanded: true,
          approved: false,
          subtasks: [
            {
              taskID: 3,
              taskName: 'Plan budget',
              startDate: new Date('02/03/2017'),
              endDate: new Date('02/07/2017'),
              duration: 15,
              progress: 100,
              priority: 'Low',
              isExpanded: false,
              approved: true,
              subtasks: [
                {
                  taskID: 4,
                  taskName: 'Allocate resources',
                  startDate: new Date('02/03/2017'),
                  endDate: new Date('02/07/2017'),
                  duration: 25,
                  progress: 100,
                  priority: 'Critical',
                  approved: false,
                },
                {
                  taskID: 5,
                  taskName: 'Planning complete',
                  startDate: new Date('02/07/2017'),
                  endDate: new Date('02/07/2017'),
                  duration: 30,
                  progress: 0,
                  priority: 'Low',
                  approved: true,
                },
              ],
            },
          ],
        },
      ],
    },
  ];

Persist expanded and collapsed states on page refresh using localStorage

To persist the expanded and collapsed state of rows using the dataBound event when the page refreshes in the browser, this guide illustrates how to utilize localStorage to save and retrieve the state of rows.

  1. Save the collapsed record’s primarykey value to localStorage in the collapsed event of the Tree Grid by using the setItem method of the local storage.
  2. On page refresh, the dataBound event will be triggered. In that event, retrieve the saved records by using the getItem method of the local storage.
  3. Then, collapsed the specific rows by using the CollapseByKey method of Tree Grid by passing the primary key value as a parameter. and collapse the specific rows by using the [collapseRow] method of the Tree Grid by passing the row detail.

In the following demo, the above-mentioned steps have been followed to persist the expanded or collapsed state while refreshing the page in the browser.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { sampleData } from './datasource';
import { TreeGridComponent } from '@syncfusion/ej2-angular-treegrid';

@Component({
    imports: [TreeGridModule,],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    selector: 'app-container',
    template: `<div class="control-section">
               <ejs-treegrid #treegrid1 [dataSource]="data" allowPaging="true" childMapping="subtasks" height="250" [treeColumnIndex]="1"
                (dataBound)="dataBound($event)" (collapsed)="collapsed($event)" (expanded)="expanded($event)" [enablePersistence]=true>
                   <e-columns>
                      <e-column field="taskID" headerText="Task ID" isPrimaryKey="true" width="70" textAlign="Right" ></e-column>
                      <e-column field="taskName" headerText="Task Name" width="200"></e-column>
                      <e-column field="startDate" headerText="Start Date" width="90" format="yMd" textAlign="Right"></e-column>
                      <e-column field="endDate" headerText="End Date" width="90" format="yMd" textAlign="Right"></e-column>
                      <e-column field="duration" headerText="Duration" width="80" textAlign="Right"></e-column>
                      <e-column field="progress" headerText="Progress" width="80" ></e-column>
                      <e-column field="priority" headerText="Priority" width="90"></e-column>   
                    </e-columns>
                  </ejs-treegrid>
              </div>`,
})
export class AppComponent implements OnInit {
    public data: Object[] = [];
    @ViewChild('treegrid1')
    public treegrid: TreeGridComponent | undefined;
    public collapsingData: any = [];

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

    dataBound(args: any): void {
        //checking whether it is initial rendering
        if (
            (this.treegrid as TreeGridComponent).initialRender &&
            window.localStorage != null
        ) {
            //retriving collapsed record in local storage using getItem method
            var Collapsed_storagedata = JSON.parse(
                window.localStorage.getItem('collapsingData') as any
            );

            if (Collapsed_storagedata != null) {
                for (var i = 0; i < Collapsed_storagedata.length; i++) {
                    (this.treegrid as TreeGridComponent).collapseByKey(
                        Collapsed_storagedata[i]
                    ); //collapsing row using collapseByKey method
                }
            }
        }
    }

    collapsed(args: any): void {
        //Here collected the collapsed record's primarykey value
        this.collapsingData.push((args.data as any).taskID);

        //Here set/ update the localstorage value
        this.setstorage_data(this.collapsingData);
    }
    expanded(args: any): void {
        //Check whether the collapsing data array has the same primary key value as the expanding data.
        var index = this.collapsingData.findIndex((x: any) => {
            if (x == (args.data as any).taskID) {
                return x;
            }
        });
        //if yes here we remove that primary key value
        this.collapsingData.splice(index, 1);

        // update the localstorage value
        this.setstorage_data(this.collapsingData);
    }
    setstorage_data(data: any): void {
        window.localStorage.setItem('collapsingData', JSON.stringify(data));
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Programmatically expand and collapse a row

In the Tree Grid, you can programmatically expand and collapse rows using various methods provided by the tree grid. This guide demonstrates how to leverage these methods to control the expansion and collapse of rows based on different criteria.

To expand all rows in the tree grid, use the expandAll method.

this.treegrid.expandAll();

To collapse all rows in the tree grid, use the collapseAll method.

this.treegrid.collapseAll();

To expand the records at a specific hierarchical level, use the expandAtLevel method.

this.treegrid.expandAtLevel(0);

To collapse the records at a specific hierarchical level, use the collapseAtLevel method.

this.treegrid.collapseAtLevel(0);

To expand records based on a given primary key value, use the expandByKey method.

this.treegrid.expandByKey(1); //Here pass the primary key value

To collapse records based on a given primary key value, use the collapseByKey method

this.treegrid.collapseByKey(1);//Here pass the primary key value

To expand child rows based on the row element, use the expandRow method.

this.treegrid.expandRow(tr); //Here pass the row element as parameter

To collapse child rows based on the row element, use the collapseRow method.

this.treegrid.collapseRow(tr);//Here pass the row element as parameter

Expand and collapse action events

In the Tree Grid, you can customize the behavior and perform specific actions when the expand or collapse icon is clicked. This can be achieved using a set of events provided by the tree grid.

The following events are available for handling expand and collapse actions:

  • expanding: This event is triggered before a row is expanded. You can perform custom actions or cancel the row expansion based on certain conditions.

  • expanded: This event is triggered after a row is expanded. You can perform additional actions or updates after the row expansion is completed.

  • collapsing: This event is triggered before a row is collapsed. You can perform custom actions or cancel the row collapse based on certain conditions.

  • collapsed: This event is triggered after a row is collapsed. You can perform additional actions or updates after the row collapse is completed.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { PageService, SortService, FilterService } from '@syncfusion/ej2-angular-treegrid'
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { sampleData } from './datasource';
import { TreeGridComponent } from '@syncfusion/ej2-angular-treegrid';

@Component({
    imports: [TreeGridModule,],
    providers: [PageService, SortService, FilterService],
    standalone: true,
    selector: 'app-container',
    template: `<div class="control-section">
                <div style="margin-left:180px"><p style="color:red;" id="message"></p></div>
          
                    <ejs-treegrid #treegrid [dataSource]="data" allowPaging="true" childMapping="subtasks" height="250"
                      [treeColumnIndex]="1" (expanding)="expanding($event)" (collapsing)="collapsing($event)" (collapsed)="collapsed($event)"
                      (expanded)="expanded($event)">
                          <e-columns>
                            <e-column field="taskID" headerText="Task ID" isPrimaryKey="true" width="70" textAlign="Right" ></e-column>
                            <e-column field="taskName" headerText="Task Name" width="200"></e-column>
                            <e-column field="startDate" headerText="Start Date" width="90" format="yMd" textAlign="Right"></e-column>
                            <e-column field="endDate" headerText="End Date" width="90" format="yMd" textAlign="Right"></e-column>
                            <e-column field="duration" headerText="Duration" width="80" textAlign="Right"></e-column>
                            <e-column field="progress" headerText="Progress" width="80" ></e-column>
                            <e-column field="priority" headerText="Priority" width="90"></e-column>   
                          </e-columns>
                     </ejs-treegrid>
               </div>`,
})
export class AppComponent implements OnInit {
    public data: Object[] = [];
    public message?: string;
    ngOnInit(): void {
        this.data = sampleData;
    }

    expanding(args: any): void {
        this.message = 'Expanding event is triggered';
    }
    collapsing(args: any): void {
        this.message = 'Collapsing event is triggered';
    }
    expanded(args: any): void {
        this.message = 'Expanded event is triggered';
    }
    collapsed(args: any): void {
        this.message = 'Collapsed event is triggered';
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));