Detail template in Angular TreeGrid component

7 Nov 202422 minutes to read

The detail template in the TreeGrid component allows you to display additional information about a specific row in the tree grid. This feature is useful when you need to show additional data or custom content that is specific to each row in the tree grid. You can use the detailTemplate property to define an HTML template for the detail row. This template can include any HTML element or Angular component that you want to display as detail content.

Here’s an example of using the detailTemplate property in the tree grid:

import { Component, OnInit, ViewEncapsulation, ViewChild } from '@angular/core';
import { TreeGridComponent, DetailRowService } from '@syncfusion/ej2-angular-treegrid';
import { textdata } from './datasource';
import { Internationalization } from '@syncfusion/ej2-base';

let instance: Internationalization = new Internationalization();

@Component({
    selector: 'app-container',
    template: `<ejs-treegrid #treegrid [dataSource]='data' height=317 width='auto' childMapping= 'Children' >
                    <e-columns>
                        <e-column field='Name' headerText='First Name' width='160'></e-column>
                        <e-column field='DOB' headerText = 'DOB' width='105' type='date' format='yMd'></e-column>
                        <e-column field='Designation' headerText = 'Designation' width='180'></e-column>
                        <e-column field='Country' headerText = 'Country' width='148'></e-column>
                    </e-columns>
                    <ng-template #detailTemplate let-data>
                        <div>
                            <div style="position: relative; display: inline-block; float: left; font-weight: bold; width: 10%;padding:5px 4px 2px 27px;;">
                                <img src="{{data.FullName}}.png" alt="{{data.FullName}}" />
                            </div>
                            <div style="padding-left: 10px; display: inline-block; width: 66%; text-wrap: normal;font-size:13px;font-family:'Segoe UI';">
                                <div class="e-description" style="word-wrap: break-word;">
                                    <b>{{data.Name}}</b> was born on {{format(data.DOB)}}. Now lives at {{data.Address}}, {{data.Country}}. {{data.Name}} holds a position of <b>{{data.Designation}}</b> in our WA department, (Seattle USA).
                                </div>
                                <div class="e-description" style="word-wrap: break-word;margin-top:5px;">
                                    <b style="margin-right:10px;">Contact:</b>{{data.Contact}}
                                </div>
                            </div>
                        </div>
                    </ng-template>
                </ejs-treegrid>`,
providers: [DetailRowService]
})
export class AppComponent implements OnInit {

    public data?: Object[];

    @ViewChild('treegrid')
    public treegrid?: TreeGridComponent;

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

    public format(value: Date): string {
        return instance.formatDate(value, { skeleton: 'yMd', type: 'date' });
    }
}
export interface DateFormat extends Window {
    format?: Function;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Rendering custom component

The TreeGrid component provides a powerful feature that allows you to render custom components inside the detail row. This feature is helpful when you need to add additional information or functionality for a specific row in the tree grid.

To render a custom component inside the detail row, you need to define a template using the detailTemplate property and handle the detailDataBound event. This template can include any HTML element or Angular component that you want to display as the detail content.

The detailDataBound event is triggered after a detail row is bound to data. This event provides an object of type DetailDataBoundEventArgs as a parameter.

For example, to render grid inside the detail row, place an HTML div element as the detailTemplate and render the DIV element as Grid component in the detailDataBound event.

import { NgModule, ViewChild } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { TreeGridModule } from '@syncfusion/ej2-angular-treegrid'
import { GridModule } from '@syncfusion/ej2-angular-grids'
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { TreeGridComponent, DetailRowService, } from '@syncfusion/ej2-angular-treegrid';
import { sampleData, textdata } from './datasource';
import { Internationalization } from '@syncfusion/ej2-base';
import { DetailDataBoundEventArgs, Grid } from '@syncfusion/ej2-grids';

let instance: Internationalization = new Internationalization();

@Component({
    imports: [TreeGridModule, GridModule],
    standalone: true,
    selector: 'app-container',
    template: `<ejs-treegrid #treegrid [dataSource]='data' height=317 width='auto' childMapping= 'Children' (detailDataBound)='detailDataBound($event)' >
                <e-columns>
                    <e-column field='Name' headerText='First Name' width='160'></e-column>
                    <e-column field='DOB' headerText = 'DOB' width='105' type='date' format='yMd'></e-column>
                    <e-column field='Designation' headerText = 'Designation' width='180'></e-column>
                    <e-column field='Country' headerText = 'Country' width='148'></e-column>
                </e-columns>
                <ng-template #detailTemplate let-data>
                    <div class = 'custom-grid' ></div>
                </ng-template>
            </ejs-treegrid>`,
    providers: [DetailRowService],
})
export class AppComponent implements OnInit {
    public data?: Object[];

    @ViewChild('treegrid')
    public treegrid?: TreeGridComponent;

    ngOnInit(): void {
        this.data = textdata;
    }
    detailDataBound(e: DetailDataBoundEventArgs) {
        let detail = new Grid({
            dataSource: sampleData,
            columns: [
                { field: 'taskID', headerText: 'Order ID', width: 110 },
                { field: 'taskName', headerText: 'Customer Name', width: 140 },
                { field: 'priority', headerText: 'Ship Country', width: 150 },
            ],
        });
        detail.appendTo(
            (e.detailElement as HTMLElement).querySelector(
                '.custom-grid'
            ) as HTMLElement
        );
    }
    public format(value: Date): string {
        return instance.formatDate(value, { skeleton: 'yMd', type: 'date' });
    }
}
export interface DateFormat extends Window {
    format?: Function;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Custom button in custom column to hide or show detail template

You can display or conceal the detail row by utilizing a custom button through the column template feature of the Tree Grid.

The column template feature provides options to render a custom component in a TreeGrid column instead of a field value. You can achieve this by utilizing the template property of the Tree Grid. This property allows you to display custom elements in a column instead of the field value. It is advantageous when you wish to display images, buttons, or other customized content within a column.

For more information about column template, refer this section.

Here’s an illustrative example showcasing how to implement showing/hiding a detail row using the column template. Utilize the column template to render a button. In the button click event, retrieve the detail row and add a CSS class to the detail row element. Based on the CSS class, you can toggle the visibility of the detail row.

import { Component, OnInit, ViewEncapsulation, ViewChild } from '@angular/core';
import {
  TreeGridComponent,
  DetailRowService,
} from '@syncfusion/ej2-angular-treegrid';
import { textdata } from './datasource';
import { Internationalization } from '@syncfusion/ej2-base';
import { CommandModel } from '@syncfusion/ej2-grids';

let instance: Internationalization = new Internationalization();

@Component({
  selector: 'app-container',
  encapsulation: ViewEncapsulation.None,
  template: `<ejs-treegrid #treegrid [dataSource]='data' height=317 width='auto'  childMapping= 'Children'  >
                <e-columns>
                    <e-column field='Name' headerText='First Name' width='160'></e-column>
                    <e-column field='DOB' headerText = 'DOB' width='105' type='date' format='yMd'></e-column>
                    <e-column field='Designation' headerText = 'Designation' width='180'></e-column>
                    <e-column field='Country' headerText = 'Country' width='148'></e-column>
                    <e-column headerText = 'Show or hide Button' width='250'>
                      <ng-template #template let-data>
                        <div class="e-section-control">
                         <button ejs-button cssClass="e-flat" content="Hide/Show Detail Row" (click)="detailrow($event)"></button>
                         </div>
                      </ng-template>
                    </e-column>
                </e-columns>
                <ng-template #detailTemplate let-data>
                 <div>
                  <div style="position: relative; display: inline-block; float: left; font-weight: bold; width: 10%;padding:5px 4px 2px 27px;;">
                    <img src="{{data.FullName}}.png" alt="{{data.FullName}}" />
                  </div>
                  <div style="padding-left: 10px; display: inline-block; width: 66%; text-wrap: normal;font-size:13px;font-family:'Segoe UI';">
                    <div class="e-description" style="word-wrap: break-word;">
                         <b>{{data.Name}}</b> was born on {{format(data.DOB)}}. Now lives at {{data.Address}}, {{data.Country}}. {{data.Name}} holds a position of <b>{{data.Designation}}</b> in our WA department, (Seattle USA).
                    </div>
                    <div class="e-description" style="word-wrap: break-word;margin-top:5px;">
                       <b style="margin-right:10px;">Contact:</b>{{data.Contact}}
                    </div>
                  </div>
                 </div>
                </ng-template>
              </ejs-treegrid>`,
  styles: [
    `.e-hidedetailrow{
    display: none; /*//hide detailrow*/
    }`,
  ],
  providers: [DetailRowService],
})
export class AppComponent implements OnInit {
  public data?: Object[];

  @ViewChild('treegrid')
  public treegrid?: TreeGridComponent;

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

  detailrow(args: any) {
    //Here get the corresponding row of the button clicked
    var target_row = args.target.closest('.e-row');

    //Check whether the next row is a detail row and if it is, determine if it is hidden or not.
    if (
      target_row.nextSibling.classList.contains('e-hidedetailrow') &&
      target_row.nextSibling.classList.contains('e-detailrow')
    ) {
      target_row.nextSibling.classList.remove('e-hidedetailrow');
    } else if (target_row.nextSibling.classList.contains('e-detailrow')) {
      target_row.nextSibling.classList.add('e-hidedetailrow');
    }
  }

  public format(target_rowue: Date): string {
    return instance.formatDate(target_rowue, { skeleton: 'yMd', type: 'date' });
  }
}
export interface DateFormat extends Window {
  format?: Function;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Render detail template for only parent records

In the Tree Grid, you have the capability to render the detail row exclusively for parent records based on a condition. The detailTemplate property allows you to include any HTML element or Angular component that you wish to display as the detail content, contingent on a condition.

In the following demonstration, the detail row is presented only for parent records using a condition in the ng-template.

import { Component, OnInit, ViewEncapsulation, ViewChild } from '@angular/core';
import {
  TreeGridComponent,
  DetailRowService,
} from '@syncfusion/ej2-angular-treegrid';
import { textdata } from './datasource';
import { Internationalization } from '@syncfusion/ej2-base';

let instance: Internationalization = new Internationalization();

@Component({
  selector: 'app-container',
  template: `<ejs-treegrid #treegrid [dataSource]='data' height=317 width='auto' childMapping= 'Children' >
                <e-columns>
                    <e-column field='Name' headerText='First Name' width='160'></e-column>
                    <e-column field='DOB' headerText = 'DOB' width='105' type='date' format='yMd'></e-column>
                    <e-column field='Designation' headerText = 'Designation' width='180'></e-column>
                    <e-column field='Country' headerText = 'Country' width='148'></e-column>
                </e-columns>
                <ng-template #detailTemplate let-data>
                  <div *ngIf="data.hasChildRecords">
                      <div style="position: relative; display: inline-block; float: left; font-weight: bold; width: 10%;padding:5px 4px 2px 27px;;">
                           <img src="{{data.FullName}}.png" alt="{{data.FullName}}" />
                      </div>
                      <div style="padding-left: 10px; display: inline-block; width: 66%; text-wrap: normal;font-size:13px;font-family:'Segoe UI';">
                          <div class="e-description" style="word-wrap: break-word;">
                             <b>{{data.Name}}</b> was born on {{format(data.DOB)}}. Now lives at {{data.Address}}, {{data.Country}}. {{data.Name}} holds a position of <b>{{data.Designation}}</b> in our WA department, (Seattle USA).
                          </div>
                          <div class="e-description" style="word-wrap: break-word;margin-top:5px;">
                            <b style="margin-right:10px;">Contact:</b>{{data.Contact}}
                          </div>
                      </div>
                  </div>
                 </ng-template>
              </ejs-treegrid>`,
  providers: [DetailRowService],
})
export class AppComponent implements OnInit {
  public data?: Object[];

  @ViewChild('treegrid')
  public treegrid?: TreeGridComponent;

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

  public format(value: Date): string {
    return instance.formatDate(value, { skeleton: 'yMd', type: 'date' });
  }
}
export interface DateFormat extends Window {
  format?: Function;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Limitations

Detail template is not supported with the following features:

  • Frozen rows and columns
  • Immutable mode
  • Infinite scrolling
  • Virtual scrolling
  • Print
  • Row template
  • Row spanning
  • Column spanning
  • State persistence