Mauricio Gracia Gutierrez
Mauricio Gracia Gutierrez

Reputation: 10862

How to return a Excel file to be downloaded on button click using JQuery and ASP.NET MVC4

I have the following method ExportarIntervalos in the Controller "MetasComisionesController"

    [HttpPost]
    public ActionResult ExportarIntervalos()
    {
        var products = new System.Data.DataTable("teste");
        products.Columns.Add("col1", typeof(int));
        products.Columns.Add("col2", typeof(string));

        products.Rows.Add(1, "product 1");
        products.Rows.Add(2, "product 2");
        products.Rows.Add(3, "product 3");
        products.Rows.Add(4, "product 4");
        products.Rows.Add(5, "product 5");
        products.Rows.Add(6, "product 6");
        products.Rows.Add(7, "product 7");


        var grid = new GridView();
        grid.DataSource = products;
        grid.DataBind();

        Response.ClearContent();
        Response.Buffer = true;
        Response.AddHeader("content-disposition", "attachment; filename=MyExcelFile.xls");
        Response.ContentType = "application/ms-excel";

        Response.Charset = "";
        StringWriter sw = new StringWriter();
        HtmlTextWriter htw = new HtmlTextWriter(sw);

        grid.RenderControl(htw);

        Response.Output.Write(sw.ToString());
        Response.Flush();
        Response.End();

        return View("ExportacionExcel");
    }

I have the following javascript code:

function btnExportar() {


    var r = confirm("Desea exportar todos los Intervalos de Comision ?");

    if (r == true) {
        //window.alert("Iniciar Exportacion");

        $.post("@Url.Action("ExportarIntervalos")",{},

            function (data) {
                alert("La EXPORTACION TERMINO");
                window.location = "/MetasComisiones/" + "ExportacionExcel";
            });


    } else {
        window.alert("Exportacion CANCELADA");
    }
}

Which is called from a button onclick event

<button type="button" class="btn" name="btnExportar" onclick="btnExportar()">Exportar</button>

How can I change any of the previous components or logic to make the button btnExportar return a file that has to be downloaded as part of the response ? I don't really need to redirect to a new location

Upvotes: 1

Views: 3429

Answers (2)

Ishan
Ishan

Reputation: 295

<script src="//cdn.rawgit.com/rainabba/jquery-table2excel/1.1.0/dist/jquery.table2excel.min.js"></script>

    $("#Xcel").click(function () {
        $("#Tab").table2excel({
            exclude: '.exclude',
            filename: 'MatchedSDNListNames.xls'
        });
    })

Can be used to import table directly.

Upvotes: 0

David
David

Reputation: 219057

Instead of writing to the response and then returning a view, simply return a file response. Normally this is trivial for an actual file system file, or at least a stream, but it shouldn't be difficult for your string either.

Perhaps something like this:

var fileContent = sw.ToString();
var fileBytes = Encoding.UTF8.GetBytes(fileContent);
var result = new FileContentResult(fileBytes, "application/ms-excel");
result.FileDownloadName = "MyExcelFile.xls";

return result;

An added benefit here is that by removing references to Response and just returning a result, you can more effectively unit test this method as well.


The problem however is the client-side code. Unless something has changed recently, AJAX can't be used for downloading files. You can download the data (in that the data variable in your client-side callback function will contain the response), but to my knowledge there's no way (outside of things like ActiveX objects, which you really don't want to use) to prompt the user to save that response as a file.

The good news, however, is that a file response doesn't unload the page content in a browser. So you don't really need to use AJAX per se, just direct the user to the request for the file. (Or, if the browser is configured to view the file content instead of prompt to save it, direct the user in a new tab/window.)

Since there's no data actually being posted, just do a normal redirect:

window.location = '@Url.Action("ExportarIntervalos")';

(And remember to remove the [HttpPost] attribute from the controller action, since this would be a GET request. If you need to use a POST then you'd probably want to put a hidden form on your page and then just call .submit() on that form in code.)

Upvotes: 3

Related Questions