Export Multiple Grids
This demo shows two DataGrids in different tabs. Click the Export multiple grids button to export two grids and arrange them on different pages of the PDF document.
To implement this functionality, call the exportDataGrid(options) methods in a chain of Promises, one after another. Use the jsPDF.addPage() method to add a page in the PDF document.
You can use the customizeCell function to customize cell appearance in the PDF document. In this demo, the customizeCell function highlights alternate (even) rows.
Feel free to share demo-related thoughts here.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Thank you for the feedback!
If you have technical questions, please create a support ticket in the DevExpress Support Center.
Backend API
<div id="exportContainer">
<dx-button
text="Export multiple grids"
icon="exportpdf"
(onClick)="exportGrids($event)"
></dx-button>
</div>
<dx-tab-panel id="tabPanel" [deferRendering]="false">
<dxi-item title="Price">
<dx-data-grid
#priceDataGrid
class="data-grid"
width="100%"
[dataSource]="priceDataSource"
[showBorders]="true"
[rowAlternationEnabled]="true"
>
<dxi-column dataField="Product_ID" caption="ID" [width]="50"></dxi-column>
<dxi-column dataField="Product_Name" caption="Name"></dxi-column>
<dxi-column
dataField="Product_Sale_Price"
caption="Sale Price"
dataType="number"
format="currency"
></dxi-column>
<dxi-column
dataField="Product_Retail_Price"
caption="Retail Price"
dataType="number"
format="currency"
></dxi-column>
</dx-data-grid>
</dxi-item>
<dxi-item title="Rating">
<dx-data-grid
#ratingDataGrid
class="data-grid"
width="100%"
[dataSource]="ratingDataSource"
[showBorders]="true"
[rowAlternationEnabled]="true"
>
<dxi-column dataField="Product_ID" caption="ID" [width]="50"></dxi-column>
<dxi-column dataField="Product_Name" caption="Name"></dxi-column>
<dxi-column
dataField="Product_Consumer_Rating"
caption="Rating"
></dxi-column>
<dxi-column dataField="Product_Category" caption="Category"></dxi-column>
</dx-data-grid>
</dxi-item>
</dx-tab-panel>
import {
NgModule, Component, ViewChild, enableProdMode,
} from '@angular/core';
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
DxButtonModule, DxTabPanelModule, DxDataGridModule, DxDataGridComponent,
} from 'devextreme-angular';
import { exportDataGrid } from 'devextreme/pdf_exporter';
import { jsPDF } from 'jspdf';
import 'devextreme/data/odata/store';
if (!/localhost/.test(document.location.host)) {
enableProdMode();
}
@Component({
selector: 'demo-app',
templateUrl: 'app/app.component.html',
styleUrls: ['app/app.component.css'],
})
export class AppComponent {
@ViewChild('priceDataGrid', { static: false }) priceDataGrid: DxDataGridComponent;
@ViewChild('ratingDataGrid', { static: false }) ratingDataGrid: DxDataGridComponent;
priceDataSource: any;
ratingDataSource: any;
constructor() {
this.priceDataSource = {
store: {
type: 'odata',
url: 'https://js.devexpress.com/Demos/DevAV/odata/Products',
key: 'Product_ID',
},
select: ['Product_ID', 'Product_Name', 'Product_Sale_Price', 'Product_Retail_Price'],
filter: ['Product_ID', '<', 10],
};
this.ratingDataSource = {
store: {
type: 'odata',
url: 'https://js.devexpress.com/Demos/DevAV/odata/Products',
key: 'Product_ID',
},
select: ['Product_ID', 'Product_Name', 'Product_Consumer_Rating', 'Product_Category'],
filter: ['Product_ID', '<', 10],
};
}
setAlternatingRowsBackground(dataGrid, gridCell, pdfCell) {
if (gridCell.rowType === 'data') {
const rowIndex = dataGrid.getRowIndexByKey(gridCell.data.Product_ID);
if (rowIndex % 2 === 0) {
pdfCell.backgroundColor = '#D3D3D3';
}
}
}
exportGrids() {
const context = this;
const doc = new jsPDF();
exportDataGrid({
jsPDFDocument: doc,
component: context.priceDataGrid.instance,
topLeft: { x: 7, y: 5 },
columnWidths: [20, 50, 50, 50],
customizeCell: ({ gridCell, pdfCell }) => {
context.setAlternatingRowsBackground(context.priceDataGrid.instance, gridCell, pdfCell);
},
}).then(() => {
doc.addPage();
exportDataGrid({
jsPDFDocument: doc,
component: context.ratingDataGrid.instance,
topLeft: { x: 7, y: 5 },
columnWidths: [20, 50, 50, 50],
customizeCell: ({ gridCell, pdfCell }) => {
context.setAlternatingRowsBackground(context.ratingDataGrid.instance, gridCell, pdfCell);
},
}).then(() => {
doc.save('MultipleGrids.pdf');
});
});
}
}
@NgModule({
imports: [
BrowserModule,
BrowserTransferStateModule,
DxButtonModule,
DxTabPanelModule,
DxDataGridModule,
],
declarations: [AppComponent],
bootstrap: [AppComponent],
})
export class AppModule { }
platformBrowserDynamic().bootstrapModule(AppModule);
::ng-deep #exportContainer {
text-align: right;
}
::ng-deep #tabPanel {
padding-top: 10px;
}
::ng-deep .data-grid {
padding: 10px;
}
// In real applications, you should not transpile code in the browser.
// You can see how to create your own application with Angular and DevExtreme here:
// https://js.devexpress.com/Documentation/Guide/Angular_Components/Getting_Started/Create_a_DevExtreme_Application/
window.exports = window.exports || {};
window.config = {
transpiler: 'ts',
typescriptOptions: {
module: 'system',
emitDecoratorMetadata: true,
experimentalDecorators: true,
},
meta: {
'typescript': {
'exports': 'ts',
},
'devextreme/localization.js': {
'esModule': true,
},
},
paths: {
'npm:': 'https://unpkg.com/',
},
map: {
'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js',
'typescript': 'npm:typescript@4.2.4/lib/typescript.js',
'@angular/core': 'npm:@angular/core@12.2.17',
'@angular/platform-browser': 'npm:@angular/platform-browser@12.2.17',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic@12.2.17',
'@angular/forms': 'npm:@angular/forms@12.2.17',
'@angular/common': 'npm:@angular/common@12.2.17',
'@angular/compiler': 'npm:@angular/compiler@12.2.17',
'tslib': 'npm:tslib@2.3.1/tslib.js',
'rxjs': 'npm:rxjs@7.5.3/dist/bundles/rxjs.umd.js',
'rxjs/operators': 'npm:rxjs@7.5.3/dist/cjs/operators/index.js',
'fflate': 'npm:fflate@0.4.8/esm/browser.js',
'jspdf': 'npm:jspdf@2.5.1/dist/jspdf.umd.min.js',
'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js',
'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js',
'es6-object-assign': 'npm:es6-object-assign@1.1.0',
'devextreme': 'npm:devextreme@23.1.6/cjs',
'devextreme/bundles/dx.all': 'npm:devextreme@23.1.6/bundles/dx.all.js',
'jszip': 'npm:jszip@3.7.1/dist/jszip.min.js',
'devextreme-quill': 'npm:devextreme-quill@1.6.2/dist/dx-quill.min.js',
'devexpress-diagram': 'npm:devexpress-diagram@2.2.2',
'devexpress-gantt': 'npm:devexpress-gantt@4.1.49',
'devextreme-angular': 'npm:devextreme-angular@23.1.6',
'@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12',
'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js',
'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js',
'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js',
'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js',
'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js',
'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js',
'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js',
'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js',
// Prettier
'prettier/standalone': 'npm:prettier@2.8.4/standalone.js',
'prettier/parser-html': 'npm:prettier@2.8.4/parser-html.js',
},
packages: {
'app': {
main: './app.component.ts',
defaultExtension: 'ts',
},
'devextreme': {
defaultExtension: 'js',
},
'devextreme/events/utils': {
main: 'index',
},
'devextreme/events': {
main: 'index',
},
'es6-object-assign': {
main: './index.js',
defaultExtension: 'js',
},
'rxjs': {
defaultExtension: 'js',
},
'rxjs/operators': {
defaultExtension: 'js',
},
},
packageConfigPaths: [
'npm:@devextreme/*/package.json',
'npm:@devextreme/runtime@3.0.12/inferno/package.json',
'npm:@angular/*/package.json',
'npm:@angular/common@12.2.17/*/package.json',
'npm:rxjs@7.5.3/package.json',
'npm:rxjs@7.5.3/operators/package.json',
'npm:devextreme-angular@23.1.6/*/package.json',
'npm:devextreme-angular@23.1.6/ui/*/package.json',
'npm:devextreme-angular@23.1.6/package.json',
'npm:devexpress-diagram@2.2.2/package.json',
'npm:devexpress-gantt@4.1.49/package.json',
],
};
System.config(window.config);
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>DevExtreme Demo</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/23.1.5/css/dx.light.css" />
<script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.12.0/dist/zone.js"></script>
<script src="https://unpkg.com/reflect-metadata@0.1.13/Reflect.js"></script>
<script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script>
<script src="config.js"></script>
<script>
System.import("app").catch(console.error.bind(console));
</script>
</head>
<body class="dx-viewport">
<div class="demo-container">
<demo-app>Loading...</demo-app>
</div>
</body>
</html>