Client-Side Exporting

View Demo Watch Video

Prerequisites and Restrictions

Client-side export requires a third-party library called JSZip. In a modular environment, it is included in the DevExtreme dependencies and is activated automatically in most of the applications. However, this does not apply to apps created with Angular CLI 6+. In such apps, you need to register JSZip.

If your app does not use modules, reference the library on your page before the DevExtreme files:

HTML
<!-- A CDN link -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
<!-- or a local script -->
<script type="text/javascript" src="js/jszip.min.js"></script>
<!-- ... -->
<!-- DevExtreme files are referenced here -->

The following restrictions apply when exporting data on the client side:

  • Only XLSX files are supported.
  • Only visible columns are exported.*
  • Modifications made in the cell and row templates, master-detail interface, and data mapping are omitted. You can use calculated columns instead of the latter.
  • Excel limits the number of grouping levels to 7, while in the DataGrid it is unlimited.
  • Client-side export in Safari on MacOS is possible only through a proxy on the server.
* - See the onExporting option description for a workaround.

User Interaction

A user can click the Export button to save an Excel file with the exported data. Data types, sorting, filtering, and grouping settings are maintained.

DevExtreme HTML5 JavaScript DataGrid Export Button

To allow a user to export data, set the export.enabled option to true.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        export: {
            enabled: true
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-export [enabled]="true"></dxo-export>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

You can disable exporting a specific column by setting its allowExporting option to false:

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        export: {
            enabled: true
        },
        columns: [{
            dataField: "id",
            allowExporting: false
        }, 
            // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-export [enabled]="true"></dxo-export>
    <dxi-column dataField="id" [allowExporting]="false"></dxi-column>
    <!-- ... -->
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

The resulting file is renamed according to the fileName option, and contains only the selected rows if you set the allowExportSelectedData option to true.

jQuery
JavaScript
$(function () {
    $("#dataGridContainer").dxDataGrid({
        // ...
        export: {
            enabled: true,
            allowExportSelectedData: true,
            fileName: "NewFileName"
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-export 
        [enabled]="true"
        [allowExportSelectedData]="true"
        fileName="NewFileName">
    </dxo-export>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

View Demo

API

Customize Excel Data

The customizeExcelCell function allows you to change the Excel cell font, background color and fill pattern, as well as align, format, and modify the cell value.

View Demo

In the code below, Excel cells are customized. Values in the Cost column are formatted according to values in the Currency column. Cells in the Product column have a different appearance if the product costs more than 3000.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        columns: ['Product', 'Cost'],
        dataSource: [
            { Product: 'Projector', Cost: 3500, Currency: '$' },
            { Product: 'Video Player', Cost: 170, Currency: '€' },
            // ...
        ],
        export: {
            enabled: true,
            customizeExcelCell: function(e) {
                if(e.gridCell.rowType === 'data') {
                    if(e.gridCell.column.dataField == "Cost") {
                        e.numberFormat = `&quot;${e.gridCell.data.Currency}&quot;#,##0.00`;
                    }
                    if(e.gridCell.column.dataField == "Product" && e.gridCell.data.Cost > 3000) {
                        e.fillPatternType = "lightGray";
                        e.fillPatternColor = "#FF0000";
                    }
                }
            }
        }
    })
})
Angular
TypeScript
HTML
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    dataSource = [
        { Product: 'Projector', Cost: 3500, Currency: '$' },
        { Product: 'Video Player', Cost: 170, Currency: '€' },
        // ...
    ];
    customizeExcelCell(e) {
        if(e.gridCell.rowType === 'data') {
            if(e.gridCell.column.dataField == "Cost") {
                e.numberFormat = `&quot;${e.gridCell.data.Currency}&quot;#,##0.00`;
            }
            if(e.gridCell.column.dataField == "Product" && e.gridCell.data.Cost > 3000) {
                e.fillPatternType = "lightGray";
                e.fillPatternColor = "#FF0000";
            }
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
<dx-data-grid 
    [columns]="['Product', 'Cost']"
    [dataSource]="dataSource">
    <dxo-export 
        [enabled]="true" 
        [customizeExcelCell]="customizeExcelCell">
    </dxo-export>
</dx-data-grid>

Hidden columns are ignored on export. If you still need to export them, use the onExporting and onExported functions. Refer to the onExporting description for an example.

Export

Call exportToExcel(selectionOnly) method to export data programmatically. When the selectionOnly parameter is false, the method exports all rows; when true - only the selected ones.

jQuery
JavaScript
// Exports selected rows
$("#dataGridContainer").dxDataGrid("instance").exportToExcel(true);
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    exportSelectedData () {
        this.dataGrid.instance.exportToExcel(true);
    };
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

Events

The DataGrid raises the following export-related events:

  • exporting
    Allows you to request export details or prevent export. Can also be used to adjust grid columns before exporting.

  • exported
    Allows you to notify an end user when exporting is completed.

  • fileSaving
    Allows you to access the exported data in the BLOB format and/or prevent it from being saved on the user's local storage.

You can handle these events with functions. Assign the handling functions to the onExporting, onExported and onFileSaving options when you configure the widget if they are going to remain unchanged at runtime.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        // ...
        onExporting: function (e) {
            // Handler of the "exporting" event
        },
        onExported: function (e) {
            // Handler of the "exported" event
        },
        onFileSaving: function (e) {
            // Handler of the "fileSaving" event
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ...
    (onExporting)="onExporting($event)"
    (onExported)="onExported($event)"
    (onFileSaving)="onFileSaving($event)">
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    onExporting (e) {
        // Handler of the "exporting" event
    };
    onExported (e) {
        // Handler of the "exported" event
    };
    onFileSaving (e) {
        // Handler of the "fileSaving" event
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})

Otherwise (or if you need several handlers for a single event), subscribe to the export-related events using the on(eventName, eventHandler) method. This approach is more typical of jQuery.

JavaScript
var exportedHandler1 = function (e) {
    // First handler of the "exported" event
};

var exportedHandler2 = function (e) {
    // Second handler of the "exported" event
};

$("#dataGridContainer").dxDataGrid("instance")
    .on("exported", exportedHandler1)
    .on("exported", exportedHandler2);
See Also

Set Up a Server-Side Proxy

If you need the export function in browsers that do not provide an API for saving files (that is, in Safari on Mac OS), implement a server-side proxy that streams the resulting file back to an end user in response to a POST request. The proxy implementation is different for each platform.

ASPx

C#
VB
using System;
using System.Web;

namespace ExportService {

    public class ExportHandler : IHttpHandler {
        public void ProcessRequest(HttpContext context) {
            if(context.Request.Form["contentType"] != null && 
               context.Request.Form["fileName"]    != null && 
               context.Request.Form["data"]        != null) {
                context.Response.Clear();
                context.Response.ContentType = context.Request.Form["contentType"].ToString();
                context.Response.Charset = "UTF-8";
                context.Response.Expires = 0;
                context.Response.AppendHeader("Content-transfer-encoding", "binary");
                context.Response.AppendHeader("Content-Disposition", 
                                              "attachment; filename=" + context.Request.Form["fileName"].ToString());
                context.Response.BinaryWrite(Convert.FromBase64String(context.Request.Form["data"].ToString()));
                context.Response.Flush();
                context.Response.End();
            }
        }
        public bool IsReusable {
            get { return false; }
        }
    }

}
Imports System
Imports System.Web

Namespace ExportService

    Public Class ExportHandler
        Implements IHttpHandler

        Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
            If context.Request.Form("contentType") IsNot Nothing AndAlso
               context.Request.Form("fileName")    IsNot Nothing AndAlso
               context.Request.Form("data")        IsNot Nothing Then
                context.Response.Clear()
                context.Response.ContentType = context.Request.Form("contentType").ToString()
                context.Response.Charset = "UTF-8"
                context.Response.Expires = 0
                context.Response.AppendHeader("Content-transfer-encoding", "binary")
                context.Response.AppendHeader("Content-Disposition", "attachment; filename=" & context.Request.Form("fileName").ToString())
                context.Response.BinaryWrite(Convert.FromBase64String(context.Request.Form("data").ToString()))
                context.Response.Flush()
                context.Response.End()
            End If
        End Sub

        Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
            Get
                Return False
            End Get
        End Property
    End Class

End Namespace

PHP

<?php
    if(!empty($_POST["data"]) && !empty($_POST["contentType"]) && !empty($_POST["fileName"])) {
    header("Access-Control-Allow-Origin: *");
    header("Content-type: {$_POST['contentType']};\n");
    header("Content-Transfer-Encoding: binary");
    header("Content-length: ".strlen($_POST['data']).";\n");
    header("Content-disposition: attachment; filename=\"{$_POST['fileName']}\"");
    die(base64_decode($_POST["data"]));
    } 
?>

Usage

Specify the export.proxyUrl option to make the widget export a file through the proxy.