简体   繁体   中英

Export to Excel automatically using Kendo Grid

I have an asp.net MVC5 project where I'm using the Kendo Grid to display table data and provide the user with Export-to-Excel functionality. These datasets are relatively small in their column counts. eg mostly 3-6 columns. However, I have some skeptical users that would like to be able to see the data that feeds some Kendo charting where the datasets are larger than I'd care to place in a Grid in the view/browser.

My question is, has anyone figured out a way to tap into the 'Export-to-Excel' functionality that is part of the Grid without displaying the Grid. I like all of the additional features that the 'Export' has for pushing the data into Excel so I'm wondering if this is feasible vs. rolling my own output to a csv file that can be opened by Excel.

Wondering if there's a way to tap into the Export-to-Excel function directly from the Controller so the data is served back to the user in Excel?

Here's an example from Telerik;

VIEW GRID Widget

<script src="//cdnjs.cloudflare.com/ajax/libs/jszip/2.4.0/jszip.min.js"></script>

@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.ProductViewModel>()    
.Name("grid")    
.HtmlAttributes( new { style = "width: 900px" } )
.Columns(columns => {
    columns.Bound(p => p.ProductName).Width(300).Locked()
           .ClientFooterTemplate("Total Count: #=count#")
           .ClientGroupFooterTemplate("Count: #=count#");
    columns.Bound(p => p.UnitPrice).Width(300);
    columns.Bound(p => p.UnitsOnOrder).Width(300)
           .ClientFooterTemplate("Average: #=average#")
           .ClientGroupFooterTemplate("Average: #=average#");
    columns.Bound(p => p.UnitsInStock).Width(300)
           .ClientFooterTemplate("Min: #= min # Max: #= max #")
           .ClientGroupHeaderTemplate("Units In Stock: #= value # (Count: #= count#)");
})
.ToolBar(tools => tools.Excel())
.Pageable()
.Sortable()
.Scrollable()
.Groupable()
.Excel(excel => excel
    .FileName("Kendo UI Grid Export.xlsx")
    .Filterable(true)
    .ProxyURL(Url.Action("Excel_Export_Save", "Grid"))
)
.Reorderable(r => r.Columns(true))
.Resizable(r => r.Columns(true))
.ColumnMenu()
.DataSource(dataSource => dataSource
    .Ajax()                 
    .PageSize(7)
    .Group(g => g.Add(p => p.UnitsInStock))
    .Aggregates(aggregates =>
    {
         aggregates.Add(p => p.UnitsInStock).Min().Max().Count();
            aggregates.Add(p => p.UnitsOnOrder).Average();
            aggregates.Add(p => p.ProductName).Count();
            aggregates.Add(p => p.UnitPrice).Sum();
    })
    .Read(read => read.Action("Excel_Export_Read", "Grid"))
)
)

CONTROLLER

using System.Collections.Generic;
using System.Web.Mvc;
using Kendo.Mvc.Examples.Models;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
using System.Linq;
using System;

namespace Kendo.Mvc.Examples.Controllers
{
public partial class GridController : Controller
{
    public ActionResult Excel_Export()
    {
        return View();
    }

    public ActionResult Excel_Export_Read([DataSourceRequest]DataSourceRequest request)
    {
        return Json(productService.Read().ToDataSourceResult(request));
    }

    [HttpPost]
    public ActionResult Excel_Export_Save(string contentType, string base64, string fileName)
    {
        var fileContents = Convert.FromBase64String(base64);

        return File(fileContents, contentType, fileName);
    }
}
}

SERVICE

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;

namespace Kendo.Mvc.Examples.Models
{
public class ProductService : IDisposable
{
    private SampleEntities entities;

    public ProductService(SampleEntities entities)
    {
        this.entities = entities;
    }

    public IEnumerable<ProductViewModel> Read()
    {
        return entities.Products.Select(product => new ProductViewModel
        {
             ProductID = product.ProductID,
             ProductName = product.ProductName,
             UnitPrice = product.UnitPrice.HasValue ? product.UnitPrice.Value : default(decimal),
             UnitsInStock = product.UnitsInStock.HasValue ? product.UnitsInStock.Value : default(short),
             QuantityPerUnit = product.QuantityPerUnit,
             Discontinued = product.Discontinued,
             UnitsOnOrder = product.UnitsOnOrder.HasValue ? (int)product.UnitsOnOrder.Value : default(int),
             CategoryID = product.CategoryID,
             Category = new CategoryViewModel()
             {
                 CategoryID = product.Category.CategoryID,
                 CategoryName = product.Category.CategoryName
             },
             LastSupply = DateTime.Today
        });
    }

    public void Create(ProductViewModel product)
    {
        var entity = new Product();

        entity.ProductName = product.ProductName;
        entity.UnitPrice = product.UnitPrice;
        entity.UnitsInStock = (short)product.UnitsInStock;
        entity.Discontinued = product.Discontinued;
        entity.CategoryID = product.CategoryID;

        if (entity.CategoryID == null)
        {
            entity.CategoryID = 1;
        }

        if (product.Category != null)
        {
            entity.CategoryID = product.Category.CategoryID;
        }

        entities.Products.Add(entity);
        entities.SaveChanges();

        product.ProductID = entity.ProductID;
    }

    public void Update(ProductViewModel product)
    {
        var entity = new Product();

        entity.ProductID = product.ProductID;
        entity.ProductName = product.ProductName;
        entity.UnitPrice = product.UnitPrice;
        entity.UnitsInStock = (short)product.UnitsInStock;
        entity.Discontinued = product.Discontinued;
        entity.CategoryID = product.CategoryID;

        if (product.Category != null)
        {
            entity.CategoryID = product.Category.CategoryID;
        }

        entities.Products.Attach(entity);
        entities.Entry(entity).State = EntityState.Modified;
        entities.SaveChanges();
    }

    public void Destroy(ProductViewModel product)
    {
        var entity = new Product();

        entity.ProductID = product.ProductID;

        entities.Products.Attach(entity);

        entities.Products.Remove(entity);

        var orderDetails = entities.Order_Details.Where(pd => pd.ProductID == entity.ProductID);

        foreach (var orderDetail in orderDetails)
        {
            entities.Order_Details.Remove(orderDetail);
        }

        entities.SaveChanges();
    }

    public void Dispose()
    {
        entities.Dispose();
    }
}
}

Link: http://demos.telerik.com/aspnet-mvc/grid/excel-export

BTW, what type of Architecture is this 'Classified' as? I love it and would like to read up on it.

How about hide the grid and add your own button (or similar) to trigger the export?

For example (using the quoted code):

  1. Add a button (or add some similar hook to your charts)

     <button id="myexport">Export to Excel</button>
  2. Hide grid and attach handler:

     $(document).ready(function () { $("#grid").hide(); $("#myexport").click(function () { var grid = $("#grid").data("kendoGrid"); grid.saveAsExcel(); }); });

The architecture in your example is ASP.NET MVC.

Another way is to use jQuery to fire the lookup when something on your page is clicked, like a <div> with id="export" :

$('#export').click(function (e) {
    $.ajax({
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        url: 'Grid/Excel_Export_Save',
        async: false,
        success: exportCSV,
    });
});

You can write your own export function. We have a way to export to CSV here which looks like this:

function exportCSV(json) {
    var csv = 'Product ID,Name,Unit Price,Qty In Stock,Discontinued,Category ID\n';
    var download = 'products.csv';
    $.each(json.Data, function (index, rowArray) {
        var row = [];
        row.push(rowArray.ProductID);
        row.push(rowArray.ProductName);
        row.push(rowArray.UnitPrice);
        row.push(rowArray.UnitsInStock);
        row.push(rowArray.Discontinued);
        row.push(rowArray.CategoryID);
        csv += row.join(',') + '\r\n';
    });
    var hiddenElement = document.createElement('a');
    hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
    hiddenElement.target = '_blank';
    hiddenElement.download = download;
    hiddenElement.click();
};

To call that, you will need to make a function in your Controller that allows Json Requests:

public async Task<JsonResult> GetGapReport([DataSourceRequest] DataSourceRequest request, String serviceType = null) {
    var result = new DataSourceResult();
    var products = new List<ProductViewModel>();
    try {
        var report = await productService.Read();
        products.AddRange(report.ToArray());
        result = products.ToDataSourceResult(request);
    } catch (Exception err) {
        result.Errors = err.Message;
    }
    return new JsonResult {
      Data = result, 
      JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
      MaxJsonLength = Int32.MaxValue 
    };
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM