New to Telerik UI for ASP.NET MVCStart a free 30-day trial

Exporting Detail Grids

Environment

ProductProgress ASP.NET MVC
Operating SystemWindows 10 64bit
Progress Telerik UI version2021.3.1207

Description

How can I export parent and child ASP.NET MVC Grids to Excel?

Solution

The following examples demonstrate how to export detail Grids to Excel and merge their workbooks with the master Grid workbook.

To get the workbook of the detail Grids, the demos use the ExcelExport event. This event is prevented to avoid the saving of an Excel file for each detail Grid. For more information on how Excel documents work, refer to the introductory help topic on Excel.

The following example demonstrates how to export a detail Grid to Excel including the current page only.

Razor
@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.EmployeeViewModel>()
        .Name("grid")
        .Columns(columns =>
        {
            columns.Bound(e => e.FirstName).Width(120);
            columns.Bound(e => e.LastName).Width(120);
            columns.Bound(e => e.Country).Width(120);
            columns.Bound(e => e.City).Width(120);
            columns.Bound(e => e.Title);
        })
        .Sortable()
        .Pageable()
        .Scrollable()
        .ToolBar(tools => tools.Excel())
        .ClientDetailTemplateId("template")
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(5)
            .Model(model => model.Id(p=>p.EmployeeID))
            .Read(read => read.Action("HierarchyBinding_Employees", "Grid"))
        )
        .Events(e => e.ExcelExport("employees_excelExport").DetailInit("employees_detailInit").DataBound("dataBound"))
)
<script id="template" type="text/kendo-tmpl">

           @(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.OrderViewModel>()
             .Name("grid_#=EmployeeID#")
             .Columns(columns =>
             {
                columns.Bound(o => o.OrderID).Title("ID").Width(80);
                columns.Bound(o => o.ShipCountry).Width(110);
                columns.Bound(o => o.ShipAddress);
                columns.Bound(o => o.ShipName).Width(190);
             })
             .DataSource(dataSource => dataSource
                .Ajax()
                .Model(model => model.Id(p=>p.OrderID))
                .PageSize(5)
                .Read(read => read.Action("HierarchyBinding_Orders", "Grid", new{ employeeID = "#=EmployeeID#" })))
            .Pageable()
            .Sortable()
            .ToClientTemplate()
           )

</script>
<script>
            function dataBound() {
                detailExportPromises = [];
                this.expandRow(this.tbody.find("tr.k-master-row").first());
            }
            var detailExportPromises = [];
            function employees_detailInit(e) {
                var deferred = $.Deferred();
                // get the index of the master row
                var masterRowIndex = e.masterRow.index(".k-master-row");
                // add the deferred to the list of promises
                detailExportPromises.push(deferred);
                var detailGrid = e.detailRow.find("[data-role=grid]").data("kendoGrid");
                detailGrid.bind("excelExport", function (e) {
                    // prevent saving the file
                    e.preventDefault();
                    // resolve the deferred
                    deferred.resolve({
                        masterRowIndex: masterRowIndex,
                        sheet: e.workbook.sheets[0]
                    });
                });
            }
            function employees_excelExport(e) {
                // prevent saving the file because we will update the workbook
                e.preventDefault();
                var workbook = e.workbook;
                // Export all detail grids
                $("[data-role=grid]", this.element).each(function () {
                    $(this).data("kendoGrid").saveAsExcel();
                });
                // wait for all detail grids to finish exporting
                $.when.apply(null, detailExportPromises)
                    .then(function () {
                        // get the export results
                        var detailExports = $.makeArray(arguments);
                        // sort by masterRowIndex
                        detailExports.sort(function (a, b) {
                            return a.masterRowIndex - b.masterRowIndex;
                        });
                        // add an empty column
                        workbook.sheets[0].columns.unshift({ width: 30 });
                        // prepend an empty cell to each row
                        for (var i = 0; i < workbook.sheets[0].rows.length; i++) {
                            workbook.sheets[0].rows[i].cells.unshift({});
                        }
                        // merge the detail export sheet rows with the master sheet rows
                        // loop backwards so the masterRowIndex doesn't need to be updated
                        for (var i = detailExports.length - 1; i >= 0; i--) {
                            var masterRowIndex = detailExports[i].masterRowIndex + 1;
                            var sheet = detailExports[i].sheet;
                            // prepend an empty cell to each row
                            for (var ci = 0; ci < sheet.rows.length; ci++) {
                                if (sheet.rows[ci].cells[0].value) {
                                    sheet.rows[ci].cells.unshift({});
                                }
                            }
                            // insert the detail sheet rows after the master row
                            [].splice.apply(workbook.sheets[0].rows, [masterRowIndex + 1, 0].concat(sheet.rows));
                        }

                        // Save the workbook.
                        new kendo.ooxml.Workbook(workbook).toDataURLAsync().then(function(data) {
                            kendo.saveAs($.extend({
                            dataURI: data,
                            fileName: "Export.xlsx"
                            }));
                        });
                    });
            }
</script>

Refer to the following REPL example for a runnable sample.

The following example demonstrates how to export a child Grid to Excel including its all pages and details. To export all Grid pages, enable the Grid's AllPages property in the Excel() configuration.

Razor
@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.EmployeeViewModel>()
        .Name("grid")
        .Columns(columns =>
        {
            columns.Bound(e => e.FirstName).Width(120);
            columns.Bound(e => e.LastName).Width(120);
            columns.Bound(e => e.Country).Width(120);
            columns.Bound(e => e.City).Width(120);
            columns.Bound(e => e.Title);
        })
        .Sortable()
        .Pageable()
        .Scrollable()
        .ToolBar(tools => tools.Excel())
        .Excel(excel=>excel.AllPages())
        .ClientDetailTemplateId("template")
        .DataSource(dataSource => dataSource
            .Ajax()
            .PageSize(5)
            .Model(model => model.Id(p=>p.EmployeeID))
            .Read(read => read.Action("HierarchyBinding_Employees", "Grid"))
        )
        .Events(e => e.ExcelExport("employees_excelExport").DetailInit("employees_detailInit").DataBound("dataBound"))
)
<script id="template" type="text/kendo-tmpl">
    @(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.OrderViewModel>()
        .Name("grid_#=EmployeeID#")
        .Columns(columns =>
        {
        columns.Bound(o => o.OrderID).Title("ID").Width(80);
        columns.Bound(o => o.ShipCountry).Width(110);
        columns.Bound(o => o.ShipAddress);
        columns.Bound(o => o.ShipName).Width(190);
        })
        .DataSource(dataSource => dataSource
        .Ajax()
        .Model(model => model.Id(p=>p.OrderID))
        .PageSize(5)
        .Read(read => read.Action("HierarchyBinding_Orders", "Grid", new{ employeeID = "#=EmployeeID#" })))
    .Pageable()
    .Sortable()
    .ToClientTemplate()
    )
</script>
<script>
    function dataBound() {
        detailExportPromises = [];
        this.expandRow(this.tbody.find("tr.k-master-row").first());
    }
    var detailExportPromises = [];
    function employees_detailInit(e) {
        var deferred = $.Deferred();
        // get the index of the master row
        var masterRowIndex = e.masterRow.index(".k-master-row");
        // add the deferred to the list of promises
        detailExportPromises.push(deferred);
        var detailGrid = e.detailRow.find("[data-role=grid]").data("kendoGrid");
        detailGrid.bind("excelExport", function (e) {
            // prevent saving the file
            e.preventDefault();
            // resolve the deferred
            deferred.resolve({
                masterRowIndex: masterRowIndex,
                sheet: e.workbook.sheets[0]
            });
        });
    }
    function employees_excelExport(e) {
        // prevent saving the file because we will update the workbook
        e.preventDefault();
        var workbook = e.workbook;
        // Export all detail grids
        $("[data-role=grid]", this.element).each(function () {
            $(this).data("kendoGrid").saveAsExcel();
        });
        // wait for all detail grids to finish exporting
        $.when.apply(null, detailExportPromises)
            .then(function () {
                // get the export results
                var detailExports = $.makeArray(arguments);
                // sort by masterRowIndex
                detailExports.sort(function (a, b) {
                    return a.masterRowIndex - b.masterRowIndex;
                });
                // add an empty column
                workbook.sheets[0].columns.unshift({ width: 30 });
                // prepend an empty cell to each row
                for (var i = 0; i < workbook.sheets[0].rows.length; i++) {
                    workbook.sheets[0].rows[i].cells.unshift({});
                }
                // merge the detail export sheet rows with the master sheet rows
                // loop backwards so the masterRowIndex doesn't need to be updated
                for (var i = detailExports.length - 1; i >= 0; i--) {
                    var masterRowIndex = detailExports[i].masterRowIndex + 1;
                    var sheet = detailExports[i].sheet;
                    // prepend an empty cell to each row
                    for (var ci = 0; ci < sheet.rows.length; ci++) {
                        if (sheet.rows[ci].cells[0].value) {
                            sheet.rows[ci].cells.unshift({});
                        }
                    }
                    // insert the detail sheet rows after the master row
                    [].splice.apply(workbook.sheets[0].rows, [masterRowIndex + 1, 0].concat(sheet.rows));
                }
                // save the workbook
                kendo.saveAs({
                    dataURI: new kendo.ooxml.Workbook(workbook).toDataURL(),
                    fileName: "Export.xlsx"
                });
            });
    }
</script>

Refer to the following REPL for a runnable sample.

To see the example on how to export all pages and all expanded detail Grids, refer to the ASP.NET MVC application in the UI for ASP.NET MVC Examples repository.

More ASP.NET MVC Grid Resources

See Also