Client-Side Exporting

Watch Video

Prerequisites and Restrictions

Client-side exporting requires a third-party library called JSZip. In a modular environment, it is included in the DevExtreme dependencies and activated automatically in most 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 in 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.
  • Exported files omit modifications the cell and row templates, master-detail interface, and data mapping make. 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.
  • Excel's data format support is limited to the predefined formats with the exception of "largeNumber", "quarterAndYear", "second", "millisecond", "quarter", "hour", and "minute".
  • Client-side exporting in Safari on MacOS is possible only through a proxy on the server.

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

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
    ],
    // ...
})

You can customize data before exporting by specifying the customizeExportData function. See an example in its description.

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.