How can I help you?
Detail Template in Angular Grid Component
19 Mar 202624 minutes to read
The detail template in the Grid component displays additional information about a specific row by expanding or collapsing detail content. This feature proves useful when additional data or custom content specific to each row requires display.The detailTemplate property is used to define the structure of this detailed content. The detailTemplate property specifies the HTML template for the detail row. This template can include any HTML element or Angular component for displaying detail content.
Common use cases for detail templates include:
- Displaying nested data or related records.
- Showing detailed information that doesn’t fit in regular columns.
- Embedding charts, forms, or other components within grid rows.
- Creating master-detail relationships between datasets.
Here’s an example of using the detailTemplate property in the Grid component:
import { GridModule, DetailRowService } from '@syncfusion/ej2-angular-grids';
import { Component, OnInit } from '@angular/core';
import { employeeData } from './datasource';
@Component({
imports: [ GridModule],
providers: [DetailRowService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid #grid [dataSource]='data' height='315' width='auto'>
<e-columns>
<e-column field="FirstName" headerText='First Name' width='140'></e-column>
<e-column field="LastName" headerText='Last Name' width='140'></e-column>
<e-column field="Title" headerText='Title' width='150'></e-column>
<e-column field="Country" headerText='Country' width='150'></e-column>
</e-columns>
<ng-template #detailTemplate let-data>
<table class="detailtable" width="100%">
<colgroup>
<col width="35%">
<col width="35%">
<col width="40%">
</colgroup>
<tbody>
<tr>
<td class="photo" rowSpan="4" style="text-align : center">
<img src="{{data.EmployeeID}}.png" alt="{{data.EmployeeID}}" />
</td>
<td>
<span style="font-weight: 500">First Name:</span>
{{data.FirstName}}
</td>
<td>
<span style="font-weight: 500"> Postal Code:</span>
{{data.PostalCode}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">Last Name:</span>
{{data.LastName}}
</td>
<td>
<span style="font-weight: 500"> City:</span>
{{data.City}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">Title:</span>
{{data.Title}}
</td>
<td>
<span style="font-weight: 500"> Phone:</span>
{{data.Phone}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">City:</span>
{{data.City}}
</td>
<td>
<span style="font-weight: 500"> Country:</span>
{{data.Country}}
</td>
</tr>
</tbody>
</table>
</ng-template>
</ejs-grid>`,
styleUrls: ['app.style.css']
})
export class AppComponent implements OnInit {
public data?: object[];
ngOnInit(): void {
this.data = employeeData;
}
}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 Grid component provides a powerful feature for rendering custom components inside the detail row. This capability proves helpful when additional information or functionality specific to a grid row requires display.
To render a custom component inside the detail row, define a template using the detailTemplate property and handle the detailDataBound event. The event is triggered after a detail row is bound to data and provides an object of type DetailDataBoundEventArgs as a parameter.
Implementation Steps:
- Create a placeholder HTML element in the detail template.
- Handle the
detailDataBoundevent to initialize the custom component. - Pass the row data to the custom component for context-aware rendering.
- Manage component life cycle and cleanup when detail rows are collapsed.
For example, to render a grid inside the detail row, place an HTML div element as the detailTemplate and render the DIV element as a grid component in the detailDataBound event:
import { columnDataType, data, employeeData } from './datasource';
import { Component, OnInit } from '@angular/core';
import { DetailDataBoundEventArgs, DetailRowService, Grid, GridModule } from '@syncfusion/ej2-angular-grids';
@Component({
imports: [ GridModule ],
providers: [DetailRowService],
standalone: true,
selector: 'app-root',
template: `<ejs-grid #grid [dataSource]='data' height='315' width='auto'
(detailDataBound)='detailDataBound($event)'>
<e-columns>
<e-column field='FirstName' headerText='First Name' width='140'>
</e-column>
<e-column field='LastName' headerText='Last Name' width='140'>
</e-column>
<e-column field='Title' headerText='Title' width='150'>
</e-column>
<e-column field='Country' headerText='Country' width='150'>
</e-column>
</e-columns>
<ng-template #detailTemplate let-data>
<div class = 'custom-grid' ></div>
</ng-template>
</ejs-grid>`
})
export class AppComponent implements OnInit {
public data?: object[];
ngOnInit(): void {
this.data = employeeData;
}
detailDataBound(e: DetailDataBoundEventArgs ) {
let detail = new Grid({
dataSource: data.filter((item: Object) => (item as columnDataType)['EmployeeID'] === (e.data as columnDataType)['EmployeeID']),
columns: [
{ field: 'OrderID', headerText: 'Order ID', width: 110 },
{ field: 'CustomerID', headerText: 'Customer Name', width: 140 },
{ field: 'ShipCountry', headerText: 'Ship Country', width: 150 }
]
});
detail.appendTo((e.detailElement as HTMLElement).querySelector('.custom-grid') as HTMLElement);
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Expand by external button
The Grid provides a feature that enables expanding the detail row using an external button. By default, detail rows render in a collapsed state with an icon in each row to expand or collapse the detail view.
Use the (https://ej2.syncfusion.com/angular/documentation/api/grid/detailRow#expand) method provided by the detailRowModule of the Syncfusion® Angular Grid library. This method expands the detail row of a specific grid row.
Key Methods for Detail Row Control:
-
expand(index: number): Expands the detail row at the specified index. -
collapse(index: number): Collapses the detail row at the specified index. -
expandAll(): Expands all detail rows in the grid. -
collapseAll(): Collapses all detail rows in the grid.
Here is an example implementation:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule } from '@syncfusion/ej2-angular-grids'
import { DetailRowService } from '@syncfusion/ej2-angular-grids'
import { ButtonModule } from '@syncfusion/ej2-angular-buttons'
import {TextBoxModule} from '@syncfusion/ej2-angular-inputs'
import { Component, OnInit, ViewChild } from '@angular/core';
import { GridComponent } from '@syncfusion/ej2-angular-grids';
import { employeeData } from './datasource';
import { TextBoxComponent } from '@syncfusion/ej2-angular-inputs';
@Component({
imports: [GridModule, ButtonModule ,TextBoxModule],
providers: [DetailRowService],
standalone: true,
selector: 'app-root',
template: `
<div style="display: inline-block; padding: 0px 30px 0px 0px">
<ejs-textbox #textbox placeholder="Enter the row Index" width="250px"
floatLabelType="Auto"></ejs-textbox>
</div>
<button ejs-button id="sample" (click)="btnClick()">Expand</button>
<div style="padding: 20px 0px 0px 0px">
<ejs-grid #grid [dataSource]="data" height="315" width="auto">
<e-columns>
<e-column field="FirstName" headerText="First Name" width="140"></e-column>
<e-column field="LastName" headerText="Last Name" width="140"></e-column>
<e-column field="Title" headerText="Title" width="150"></e-column>
<e-column field="Country" headerText="Country" width="150"></e-column>
</e-columns>
<ng-template #detailTemplate let-data>
<table class="CardTable" cellpadding="3" cellspacing="2">
<colgroup>
<col width="35%">
<col width="35%">
<col width="40%">
</colgroup>
<tbody>
<tr>
<td class="rowphoto" rowspan="4" style="text-align: center">
<img src="{{ data.EmployeeID }}.png" alt="{{ data.EmployeeID }}" />
</td>
<td>
<span style="font-weight: 500">First Name:</span>
{{ data.FirstName }}
</td>
<td>
<span style="font-weight: 500">Postal Code:</span>
{{ data.PostalCode }}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">Last Name:</span>
{{ data.LastName }}
</td>
<td>
<span style="font-weight: 500">City:</span>
{{ data.City }}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">Title:</span>
{{ data.Title }}
</td>
<td>
<span style="font-weight: 500">Phone:</span>
{{ data.Phone }}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500">City:</span>
{{ data.City }}
</td>
<td>
<span style="font-weight: 500">Country:</span>
{{ data.Country }}
</td>
</tr>
</tbody>
</table>
</ng-template>
</ejs-grid>
</div>`
})
export class AppComponent implements OnInit {
public data?: object[];
@ViewChild('grid') public grid?: GridComponent;
@ViewChild('textbox') public textbox?: TextBoxComponent;
ngOnInit(): void {
this.data = employeeData;
}
public btnClick(): void {
const rowIndex = parseInt((this.textbox as TextBoxComponent).value as string, 10);
if (!isNaN(rowIndex) && rowIndex >= 0) {
(this.grid as GridComponent).detailRowModule.expand(rowIndex);
// Expand the detail row of the specified row index
}
}
}import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));Customize detail template icon
The detail template icon in the Syncfusion® Angular Grid expands or collapses the detail content of a row. By default, the icon represents a right arrow for the collapsed state and a down arrow for the expanded state. To customize this icon, override the following CSS styles:
Default Icon CSS Classes:
-
.e-icon-grightarrow: Controls the collapsed state icon. -
.e-icon-gdownarrow: Controls the expanded state icon.
To customize these icons, override the following CSS styles:
.e-grid .e-icon-grightarrow::before {
content: "\e655"; /* Custom icon code for collapsed state */
}
.e-grid .e-icon-gdownarrow::before {
content: "\e304"; /* Custom icon code for expanded state */
}The following example demonstrates icon customization implementation:
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule } from '@syncfusion/ej2-angular-grids'
import { DetailRowService } from '@syncfusion/ej2-angular-grids'
import { Component } from '@angular/core';
import { employeeData } from './datasource';
import { Internationalization } from '@syncfusion/ej2-base';
let instance: Internationalization = new Internationalization();
@Component({
imports: [ GridModule ],
providers: [DetailRowService],
standalone: true,
selector: 'app-root',
template: `<div class="control-section">
<ejs-grid #grid [dataSource]='data' id='Grid'>
<ng-template #detailTemplate let-data>
<table class="detailtable" width="100%">
<colgroup>
<col width="35%">
<col width="35%">
<col width="30%">
</colgroup>
<tbody>
<tr>
<td rowspan="4" style="text-align: center;">
<img class='photo' src="https://ej2.syncfusion.com/angular/demos/assets/grid/images/{{data.EmployeeID}}.png" alt="{{data.EmployeeID}}" />
</td>
<td>
<span style="font-weight: 500;">First Name: </span> {{data.FirstName}}
</td>
<td>
<span style="font-weight: 500;">Postal Code: </span> {{data.PostalCode}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500;">Last Name: </span> {{data.LastName}}
</td>
<td>
<span style="font-weight: 500;">City: </span> {{data.City}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500;">Title: </span> {{data.Title}}
</td>
<td>
<span style="font-weight: 500;">Phone: </span> {{data.HomePhone}}
</td>
</tr>
<tr>
<td>
<span style="font-weight: 500;">Address: </span> {{data.Address}}
</td>
<td>
<span style="font-weight: 500;">HireDate: </span> {{format(data.HireDate)}}
</td>
</tr>
</tbody>
</table>
</ng-template>
<e-columns>
<e-column field='EmployeeID' headerText='Employee ID' width='125'
textAlign='Right'></e-column>
<e-column field='FirstName' headerText='Name' width='120'>
</e-column>
<e-column field='Title' headerText='Title' width='170'></e-column>
<e-column field='HireDate' headerText='Hire Date' width='135'
textAlign='Right' format='yMd'></e-column>
<e-column field='ReportsTo' headerText='Reports To' width='120'
textAlign='Right'></e-column>
</e-columns>
</ejs-grid>
</div>`
})
export class AppComponent {
public data?: Object[];
ngOnInit(): void {
this.data = employeeData;
}
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 functionality has the following feature limitations:
- Frozen rows and columns
- Immutable mode
- Virtual scrolling
- Row template
- Row spanning
- Column spanning
- Lazy load grouping
- State persistence
These limitations are due to architectural constraints and rendering conflicts between the detail template system and the specified features.