Pdf export in Angular Grid component

17 Sep 202524 minutes to read

The PDF export feature in the Syncfusion Angular Grid enables exporting grid data to a PDF document, allowing easy creation of printable reports or sharing data in a standardized format.

To enable PDF export in the grid, set the allowPdfExport property to true and use the pdfExport method to initiate exporting.

Make sure to inject PdfExportService in the providers section of the AppModule to use the export feature.

The following example demonstrates performing a PDF export action in the grid.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService } from '@syncfusion/ej2-angular-grids'




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

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions'
                height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=150></e-column>
                        <e-column field='ShipName' headerText='Ship Name' width=150></e-column>
                    </e-columns>
                </ejs-grid>`,
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid')
    public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') { // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            (this.grid as GridComponent).pdfExport();
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Show spinner while exporting

Displaying a spinner during the export process provides a visual indication of export progress in the Syncfusion Angular Grid.

To show or hide a spinner while exporting, use the showSpinner and hideSpinner methods. Call showSpinner on the Grid instance in the toolbarClick event when the PDF Export toolbar item is clicked. Hide the spinner after the export completes by binding the pdfExportComplete event and calling hideSpinner.

Example of showing and hiding the spinner during PDF export:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService, PageService } from '@syncfusion/ej2-angular-grids'




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

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService, PageService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [allowPaging]=true [toolbar]='toolbarOptions' height='272px' [allowPdfExport]='true' (pdfExportComplete)='pdfExportComplete()'
    (toolbarClick)='toolbarClick($event)'>
        <e-columns>
            <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
            <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
            <e-column field='ProductName' headerText='Product Name' width=110></e-column>
            <e-column field='Quantity' headerText='Quantity' width=100></e-column>
        </e-columns>
    </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid')  public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            (this.grid as GridComponent).showSpinner();
            (this.grid as GridComponent).pdfExport();
        } 
    }

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

Binding custom data source while exporting

The Syncfusion Angular Grid allows exporting a custom data source to PDF, even if that data is not already bound to the grid. This enables exporting dynamically generated or application-derived data.

Specify the dataSource property within the pdfExportProperties object. This property determines the data source for the PDF export operation.

Example demonstrating export with a dynamically defined data source:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService, PageService } from '@syncfusion/ej2-angular-grids'




import { Component, OnInit, ViewChild } from '@angular/core';
import { data, changedData } from './datasource';
import { GridComponent, ToolbarItems, PdfExportProperties } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService, PageService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [allowPaging]='true' [toolbar]='toolbarOptions'
                height='220px' [allowPaging]='true' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=110></e-column>
                        <e-column field='ShipName' headerText='Ship Name' width=120></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid') public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') { // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            const pdfExportProperties: PdfExportProperties = {
                dataSource: changedData,
            };
            (this.grid as GridComponent).pdfExport(pdfExportProperties);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Ensure to use field names in the custom data source that match the field properties of the grid columns for correct export.

Exporting with custom aggregate

Custom aggregates in the Syncfusion Angular Grid enable exporting data with additional calculated values, providing more comprehensive information in the exported file.

To use custom aggregation, set the type property to Custom and provide your aggregate function via the customAggregate property.

Within your custom function, calculate and return results (such as counts, sums, etc.) as needed.

Example: Exporting the grid with a custom aggregate showing the count of Brazil in the ShipCountry column.

import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { GridComponent, ToolbarItems, ReturnType } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';

@Component({
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions' height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=100></e-column>
                        <e-column field='ShipCountry' headerText='ShipCountry' width=100></e-column>
                    </e-columns>
                    <e-aggregates>
                        <e-aggregate>
                            <e-columns>
                                <e-column
                                columnName="ShipCountry"
                                type="Custom"
                                [customAggregate]="customAggregateFn"
                                >
                                <ng-template #footerTemplate let-data> {{ data.Custom }}
                                </ng-template>
                                </e-column>
                            </e-columns>
                        </e-aggregate>
                    </e-aggregates>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid') public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];

    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            (this.grid as GridComponent).pdfExport();
        }
    }

    public customAggregateFn = (customData: object[] | { result?: object[] }) => {
        let data: object[] = [];
    
        if ('result' in customData && Array.isArray(customData.result)) {
            data = customData.result;
        } else if (Array.isArray(customData)) {
            data = customData;
        }
    
        const brazilCount = data.filter((item: object) => (item as itemType)['ShipCountry'] === 'Brazil').length;
    
        return `Brazil count: ${brazilCount}`;
    };
}

interface itemType {
    OrderID: number;
    CustomerID: string;
    EmployeeID: number;
    OrderDate: Date;
    ShipName: string;
    ShipCountry: string;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Exporting with cell and row spanning

Exporting cell and row spans from the Syncfusion Angular Grid maintains the merged structure in the exported PDF. This is useful for preserving the layout of merged cells.

Specify rowSpan and colSpan in the queryCellInfo event. Customize export cell appearance using pdfQueryCellInfo.

Example for exporting with cell and row spanning:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService,AggregateService } from '@syncfusion/ej2-angular-grids'

import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { GridComponent, ToolbarItems, PdfQueryCellInfoEventArgs, QueryCellInfoEventArgs, Column } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';
@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService,AggregateService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' gridLines="Both" [dataSource]='data' [toolbar]='toolbarOptions' height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)' (pdfQueryCellInfo)="pdfQueryCellInfo($event)" (queryCellInfo)="queryCellInfoEvent($event)">
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                        <e-column field='Freight' headerText='Freight' width=80></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=100></e-column>
                        <e-column field='ShipCountry' headerText='Ship Country' width=100></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid') public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            (this.grid as any).pdfExport();
        }
    }

    queryCellInfoEvent = function (args: QueryCellInfoEventArgs) {

        switch ((args.data as columnDataType).OrderID) {
            case 10248:
                if ((args.column as Column).field === 'CustomerID') {
                    args.rowSpan = 2;
                }
                break;
            case 10250:
                if ((args.column as Column).field === 'CustomerID') {
                    args.colSpan = 2;
                }
                break;
            case 10252:
                if ((args.column as Column).field === 'OrderID') {
                    args.rowSpan = 3;
                }
                break;
            case 10256:
                if ((args.column as Column).field === 'CustomerID') {
                    args.colSpan = 3;
                }
                break;
            case 10261:
                if ((args.column as Column).field === 'Freight') {
                    args.colSpan = 2;
                }
                break;
        }
    }

    pdfQueryCellInfo = function (args: PdfQueryCellInfoEventArgs) {
        switch ((args.data as columnDataType).OrderID) {
            case 10248:
                if ((args.column as Column).field === 'CustomerID') {
                    (args.cell as PdfCell).rowSpan = 2;
                }
                break;
            case 10250:
                if ((args.column as Column).field === 'CustomerID') {
                    args.colSpan = 2;
                }
                break;
            case 10252:
                if ((args.column as Column).field === 'OrderID') {
                    (args.cell as PdfCell).rowSpan = 3;
                }
                break;
            case 10256:
                if ((args.column as Column).field === 'CustomerID') {
                    args.colSpan = 3;
                }
                break;
            case 10261:
                if ((args.column as Column).field === 'Freight') {
                    args.colSpan = 2;
                }
                break;
        }
    };
}

interface columnDataType{
    field: number;
    OrderID:number,
    Freight:number,
    CustomerID:string,
    ShipCity:string,
    ShipName:string,
    ShipCountry:string,
    ShipPostalCode:number
}

interface PdfCell {
    rowSpan?: number;  
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

  • The updateCell method does not support row and column spanning.

Merge duplicate cells in a specific column before exporting

Merge duplicate cells in a specified column by handling the dataBound event and use pdfQueryCellInfo during export for PDF formatting. This improves readability and presents grouped data visually.

Example: Merging duplicate cells in the OrderID column in both Grid view and export:

import { GridModule, ToolbarService, PdfExportService, PdfQueryCellInfoEventArgs, PdfExportCompleteArgs } from '@syncfusion/ej2-angular-grids'
import { Component, OnInit, ViewChild } from '@angular/core';
import { data } from './datasource';
import { GridComponent, ToolbarItems } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';
import { PdfGridCell } from '@syncfusion/ej2-pdf-export';

@Component({
    imports: [ GridModule],
    providers: [PdfExportService, ToolbarService],
    standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions'
                height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'
                (dataBound)="onDataBound()" (pdfQueryCellInfo)="pdfQueryCellInfo($event)" (pdfExportComplete)="pdfExportComplete($event)"
                >
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=120></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=150></e-column>
                        <e-column field='City' headerText='Ship City' width=150></e-column>
                    </e-columns>
                </ejs-grid>`,
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    public currentCell: PdfGridCell | null = null;
    public currentOrderID: number | null = null;;
    public cellIndexCount = 1;
    @ViewChild('grid')
    public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }
    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') { // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            (this.grid as GridComponent).pdfExport();
        }
    }
    onDataBound() {
        let previousData: number | null = null;
        let startRowIndex: number | null = null;
        let endRowIndex: number | null = null;
        let rows = (this.grid as GridComponent).getRows();
        let data = (this.grid as GridComponent).getCurrentViewRecords();

        for (let i = 0, len = rows.length; i < len; i++) {
            if (!previousData) {
                previousData = (data[i] as Order)['OrderID'];
                startRowIndex = parseInt(((rows[i] as HTMLElement).getAttribute("aria-rowindex") as string));
            }
            else if (previousData === (data[i] as Order)['OrderID']) {
                rows[i].children[0].classList.add('e-hide');
            }
            else if (previousData && previousData !== (data[i] as Order)['OrderID']) {
                if ((this.grid as GridComponent).getRows().length > 0 && (this.grid as GridComponent).getRows().length > (startRowIndex as number)) {
                    endRowIndex = parseInt(((rows[i] as HTMLElement).getAttribute("aria-rowindex") as string), 10);
                    let targetRow = (this.grid as GridComponent).getRows()[(startRowIndex as number)];
                    let currentRowChild = rows[i] && rows[i].children[0];
                    if (targetRow && currentRowChild) {
                        let targetCell = [].slice.call(targetRow.querySelectorAll('.e-rowcell')).filter((cell) =>
                            parseInt(((cell as HTMLElement).getAttribute('aria-colindex') as string), 10) === parseInt(((currentRowChild as HTMLElement).getAttribute('aria-colindex') as string))
                        );
                        if (targetCell[0]) {
                            (targetCell[0] as HTMLElement).setAttribute("rowSpan", ((endRowIndex as number) - (startRowIndex as number)).toString());
                        }
                    }
                    previousData = (data[i] as Order)['OrderID'];
                    startRowIndex = parseInt(((rows[i] as HTMLElement).getAttribute("aria-rowindex") as string), 10);
                }
            }
            if (rows[i].children[0].classList.contains("e-hide") || i < len) {
                endRowIndex = parseInt((rows[i].getAttribute("aria-rowindex") as string), 10);
                if (endRowIndex > 0) {
                    let targetRow = (this.grid as GridComponent).getRows()[(startRowIndex as number)];
                    let currentRowChild = rows[i] && rows[i].children[0];
                    if (targetRow && currentRowChild) {
                        let targetCell = [].slice.call(targetRow.querySelectorAll('.e-rowcell')).filter((cell) =>
                            parseInt(((cell as HTMLElement).getAttribute('aria-colindex') as string), 10) === parseInt(((currentRowChild as HTMLElement).getAttribute('aria-colindex') as string))
                        );
                        if (targetCell.length > 0) {
                            (targetCell[0] as HTMLElement).setAttribute("rowSpan", (endRowIndex - (startRowIndex as number) + 1).toString());
                        }
                    }
                }
            }
        }

    };
    pdfQueryCellInfo(args: PdfQueryCellInfoEventArgs) {
        if (!this.currentOrderID && args.column && args.column.field == "OrderID") {
            this.currentOrderID = (args.data as Order)["OrderID"];
            this.currentCell = args.cell as PdfGridCell;
        }
        else if (this.currentOrderID && args.column && args.column.field == "OrderID" && this.currentOrderID == (args.data as Order)["OrderID"]) {
            this.cellIndexCount++;
        } else if (this.currentOrderID !== (args.data as Order)["OrderID"] && args.column && args.column.field == "OrderID") {
            (this.currentCell as PdfGridCell).rowSpan = this.cellIndexCount;
            this.currentOrderID = (args.data as Order)["OrderID"];
            this.currentCell = args.cell as PdfGridCell;
            this.cellIndexCount = 1;
        }
    };
    // Reset the pdf export global variable values
    pdfExportComplete(args: PdfExportCompleteArgs) {
        this.currentOrderID = null;
        this.currentCell = null;
        this.cellIndexCount = 1;
    }
}

interface Order {
    OrderID: number;
    CustomerID: string;
    City: string;
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Exporting with custom date format

You can export grid data with a custom date format by using the columns.format property for grid columns. Define a custom format in the format options to format date values.

Example: The OrderDate column is exported in the format day-of-the-week, month abbreviation, day, and 2-digit year (e.g., Thu, Jul 4, ‘96).

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService,AggregateService } from '@syncfusion/ej2-angular-grids'

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

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService,AggregateService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions' height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'>
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                        <e-column field='OrderDate' headerText='Order Date' [format]='formatOptions' width=100></e-column>
                        <e-column field='Freight' headerText='Freight' width=80></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    public formatOptions?: object;
    @ViewChild('grid') public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
        this.formatOptions = { type: 'date', format: "EEE, MMM d, ''yy" };
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            (this.grid as GridComponent).pdfExport();
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Exporting multiple grids

The Syncfusion Angular Grid makes it possible to export multiple grids for comparison, either on the same page or different pages of a PDF.

Same page

Export multiple grids to a single PDF page using multipleExport.type set to AppendToPage, and multipleExport.blankSpace to define space between grids.

Example of exporting multiple grids to the same page:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService } from '@syncfusion/ej2-angular-grids'




import { Component, OnInit, ViewChild } from '@angular/core';
import { data, employeeData } from './datasource';
import { GridComponent, ToolbarItems, PdfExportProperties } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-navigations';

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService],
standalone: true,
    selector: 'app-root',
    template: `<p><b>First Grid:</b></p>
    <ejs-grid #firstGrid id='FirstGrid' [dataSource]='firstGridData' [toolbar]='toolbarOptions' [allowPdfExport]='true'
        (toolbarClick)='toolbarClick($event)' [exportGrids]='exportGrids'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=100></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=110></e-column>
                </e-columns>
                </ejs-grid>
                <p><b>Second Grid:</b></p>
                <ejs-grid #secondGrid id='SecondGrid' [dataSource]='secondGridData' [allowPdfExport]='true'>
                <e-columns>
                    <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=90></e-column>
                    <e-column field='FirstName' headerText='FirstName' width=100></e-column>
                    <e-column field='LastName' headerText='Last Name' width=100></e-column>
                    <e-column field='City' headerText='City' width=100></e-column>
                </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public firstGridData?: object[];
    public secondGridData?: object[];
    public toolbarOptions?: ToolbarItems[];
    public exportGrids?: string[];
    @ViewChild('firstGrid') public firstGrid?: GridComponent;
    @ViewChild('secondGrid') public secondGrid?: GridComponent;

    ngOnInit(): void {
        this.firstGridData = data;
        this.secondGridData = employeeData;
        this.toolbarOptions = ['PdfExport'];
        this.exportGrids = ['FirstGrid', 'SecondGrid']
    }

    toolbarClick = (args: ClickEventArgs) => {
        if (args.item.id === 'FirstGrid_pdfexport') { // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            const appendPdfExportProperties: PdfExportProperties = {
                multipleExport: { type: "AppendToPage", blankSpace: 10 }
            };
            (this.firstGrid as GridComponent).pdfExport(appendPdfExportProperties, true);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

New page

Export multiple grids to separate PDF pages with multipleExport.type set to NewPage.

Steps:

  1. Access the pdfExportProperties of the Grid component.
  2. Set multipleExport.type to NewPage.
  3. Trigger the PDF export.

Example for exporting multiple grids to separate pages:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService } from '@syncfusion/ej2-angular-grids'




import { Component, OnInit, ViewChild } from '@angular/core';
import { data, employeeData } from './datasource';
import { GridComponent, ToolbarItems, PdfExportProperties } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-navigations';

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService],
standalone: true,
    selector: 'app-root',
    template: `<p><b>First Grid:</b></p>
    <ejs-grid #firstGrid id='FirstGrid' [dataSource]='firstGridData' [toolbar]='toolbarOptions' [allowPdfExport]='true'
        (toolbarClick)='toolbarClick($event)' [exportGrids]='exportGrids'>
                <e-columns>
                    <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                    <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                    <e-column field='ShipCity' headerText='Ship City' width=100></e-column>
                    <e-column field='ShipName' headerText='Ship Name' width=110></e-column>
                </e-columns>
                </ejs-grid>
                <p><b>Second Grid:</b></p>
                <ejs-grid #secondGrid id='SecondGrid' [dataSource]='secondGridData' [allowPdfExport]='true'>
                <e-columns>
                    <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=90></e-column>
                    <e-column field='FirstName' headerText='FirstName' width=100></e-column>
                    <e-column field='LastName' headerText='Last Name' width=100></e-column>
                    <e-column field='City' headerText='City' width=100></e-column>
                </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public firstGridData?: object[];
    public secondGridData?: object[];
    public toolbarOptions?: ToolbarItems[];
    public exportGrids?: string[];
    @ViewChild('firstGrid') public firstGrid?: GridComponent;
    @ViewChild('secondGrid') public secondGrid?: GridComponent;

    ngOnInit(): void {
        this.firstGridData = data;
        this.secondGridData = employeeData;
        this.toolbarOptions = ['PdfExport'];
        this.exportGrids = ['FirstGrid', 'SecondGrid'];
    }

    toolbarClick = (args: ClickEventArgs) => {
        const appendPdfExportProperties: PdfExportProperties = {
            multipleExport: { type: 'NewPage' }
        };
        if (args.item.id === 'FirstGrid_pdfexport') { // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            (this.firstGrid as GridComponent).pdfExport(appendPdfExportProperties, true);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Limitations

  • Multiple grids exporting is not supported with server-side exporting.

Exporting hierarchy grid

Export hierarchy data, including master and child grids, to PDF using the pdfExportProperties.hierarchyExportMode property. Control export with these options:

Mode Behavior
Expanded Exports the master grid with expanded child grids.
All Exports the master grid with all child grids, regardless of their expanded state.
None Exports only the master grid.

Example: Configure hierarchy export mode using a DropDownList in the UI to change hierarchyExportMode for PDF export.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService, DetailRowService } from '@syncfusion/ej2-angular-grids'
import { DropDownListAllModule } from '@syncfusion/ej2-angular-dropdowns'

import { Component, OnInit, ViewChild } from '@angular/core';
import { data, employeeData } from './datasource';
import {
    GridComponent,
    ToolbarItems,
    PdfExportProperties,
    GridModel,
    
} from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';
import { DropDownListComponent } from '@syncfusion/ej2-angular-dropdowns';

@Component({
imports: [
        
        GridModule,
        DropDownListAllModule
    ],

providers: [PdfExportService, ToolbarService, DetailRowService],
standalone: true,
    selector: 'app-root',
    template: `
  <div style="display: flex">
    <label style="padding: 10px 10px 26px 0"> Change the hierarchy export mode: </label>
    <ejs-dropdownlist
    style="margin-top:5px"
    #dropDownList
    index="0"
    width="150"
    [dataSource]="ddlData"></ejs-dropdownlist>
    </div>
    <ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions' [childGrid]='childGrid'
    height='220px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)'>
        <e-columns>
            <e-column field='EmployeeID' headerText='Employee ID' textAlign='Right' width=90></e-column>
            <e-column field='FirstName' headerText='FirstName' width=100></e-column>
            <e-column field='LastName' headerText='Last Name' width=100></e-column>
            <e-column field='City' headerText='City' width=100></e-column>
        </e-columns>
    </ejs-grid>`
})
export class AppComponent implements OnInit {
    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid') public grid?: GridComponent;
    @ViewChild('dropDownList')
    public dropDownList?: DropDownListComponent;
    public ddlData: object[] = [
        { text: 'Expanded', value: 'Expanded' },
        { text: 'All', value: 'All' },
        { text: 'None', value: 'None' },
    ];

    public childGrid: GridModel = {
        dataSource: data,
        queryString: 'EmployeeID',
        columns: [
            {
                field: 'OrderID',
                headerText: 'Order ID',
                textAlign: 'Right',
                width: 90,
            },
            { field: 'CustomerID', headerText: 'Customer ID', width: 100 },
            { field: 'ShipCity', headerText: 'Ship City', width: 100 },
            { field: 'ShipName', headerText: 'Ship Name', width: 110 },
        ],
    };

    ngOnInit(): void {
        this.data = employeeData;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            // 'Grid_pdfexport' -> Grid component id + _ + toolbar item name
            const exportProperties: PdfExportProperties = {
                hierarchyExportMode: (this.dropDownList as DropDownListComponent).value as PdfExportProperties["hierarchyExportMode"],
            };
            (this.grid as GridComponent).pdfExport(exportProperties);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Format the child grid columns before exporting

Use the exportDetailDataBound event to customize child grid columns when exporting hierarchy grids. Adjust column formatting before the export, such as setting date formats.

Example: The OrderDate column in the child grid is formatted as dd/MM/yyyy during PDF export:

import { ViewChild} from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService, DetailRowService, GridComponent, ToolbarItems, PdfExportProperties, GridModel, DetailDataBoundEventArgs, ColumnModel } from '@syncfusion/ej2-angular-grids'
import { Component, OnInit } from '@angular/core';
import { data ,employeeData } from './datasource';
import { ClickEventArgs } from "@syncfusion/ej2-angular-navigations";
@Component({
    imports: [GridModule],
    providers: [PdfExportService, ToolbarService, DetailRowService],
    standalone: true,
    selector: 'app-root',
    template: `
    <ejs-grid #grid id="Grid" [dataSource]="data" [toolbar]="toolbarOptions" [childGrid]="childGrid" height="220px" [allowPdfExport]="true" (toolbarClick)="toolbarClick($event)" (exportDetailDataBound)="exportDetailDataBound($event)">
        <e-columns>
            <e-column field="EmployeeID" headerText="Employee ID" textAlign="Right" width="90"></e-column>
            <e-column field="FirstName" headerText="FirstName" width="100"></e-column>
            <e-column field="LastName" headerText="Last Name" width="100"></e-column>
            <e-column field="City" headerText="City" width="100"></e-column>
        </e-columns>
    </ejs-grid>`
})
export class AppComponent implements OnInit {
    @ViewChild("grid") public grid?: GridComponent;
    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    public childGrid: GridModel = {
        dataSource: data,
        queryString: "EmployeeID",
        columns: [
            { field: "OrderID", headerText: "Order ID", textAlign: "Right", width: 90 },
            { field: "CustomerID", headerText: "Customer ID", width: 100 },
            { field: "OrderDate",  headerText: "Order Date",  width: 120, format: { type: 'date', format: 'dd-MM-yyyy' }},
            { field: "ShipCity", headerText: "Ship City", width: 100 }
        ],
    };
    ngOnInit(): void {
        this.data = employeeData;
        this.toolbarOptions = ["PdfExport"];
    }
    public exportDetailDataBound(args: DetailDataBoundEventArgs): void {
        // Set the date format for the OrderDate column before exporting.
        ((args.childGrid as GridModel).columns as ColumnModel[])[2].format = { type: 'date', format: 'dd\\/MM\\/yyyy' };
    }
    public toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            const exportProperties: PdfExportProperties = {
              hierarchyExportMode: 'All',
            };
            (this.grid as GridComponent).pdfExport(exportProperties);
        }
    }
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Remove header row while exporting

To export grid data without a header row, handle the pdfHeaderQueryCellInfo event and omit content and height for header cells. This ensures only data rows are included in the exported PDF.

Example of export without a header row:

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { GridModule, ToolbarService, PdfExportService,AggregateService } from '@syncfusion/ej2-angular-grids'

import { Component, OnInit, ViewChild } from '@angular/core';
import { data, Cell } from './datasource';
import { GridComponent, ToolbarItems, PdfHeaderQueryCellInfoEventArgs } from '@syncfusion/ej2-angular-grids';
import { ClickEventArgs } from '@syncfusion/ej2-angular-navigations';

@Component({
imports: [
        
        GridModule
    ],

providers: [PdfExportService, ToolbarService,AggregateService],
standalone: true,
    selector: 'app-root',
    template: `<ejs-grid #grid id='Grid' [dataSource]='data' [toolbar]='toolbarOptions' height='272px' [allowPdfExport]='true' (toolbarClick)='toolbarClick($event)' (pdfHeaderQueryCellInfo)="pdfHeaderQueryCellInfo($event)">
                    <e-columns>
                        <e-column field='OrderID' headerText='Order ID' textAlign='Right' width=90></e-column>
                        <e-column field='CustomerID' headerText='Customer ID' width=100></e-column>
                        <e-column field='ShipCity' headerText='Ship City' width=100></e-column>
                        <e-column field='ShipCountry' headerText='Ship Country' width=100></e-column>
                    </e-columns>
                </ejs-grid>`
})
export class AppComponent implements OnInit {

    public data?: object[];
    public toolbarOptions?: ToolbarItems[];
    @ViewChild('grid') public grid?: GridComponent;

    ngOnInit(): void {
        this.data = data;
        this.toolbarOptions = ['PdfExport'];
    }

    toolbarClick(args: ClickEventArgs): void {
        if (args.item.id === 'Grid_pdfexport') {
            (this.grid as GridComponent).pdfExport();
        }
    }

    pdfHeaderQueryCellInfo({cell}: PdfHeaderQueryCellInfoEventArgs) {
        const typedCell = cell as Cell;
        typedCell.value = '';
        if (typedCell.value === '') {
            typedCell.height = '';
        }

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

See also