简体   繁体   中英

C# MVC Razor 5: location.href in an ajax call

I have a solution in my MVC project which allows me to show and/or hide a loading screen whenever I want to:

$("#divLoading").show();
$("#divLoading").hide();

This "divLoading" essentially contains the loading screen. Now this solution works fine most of the time; even if I want to use Ajax in order to show the loading screen when the script begins execution and hide it when the function is done. Something like:

$("#btnTreatData").click(function () {
    $("#divLoading").show();
    // Some stuff
    $.ajax({
        contentType: 'application/json; charset=utf-8',
        url: '@Url.Action("TreatValidationData", "Article")',
        type: "POST",
        data: JSON.stringify({ listOfCheckedData: listOfCheckedData }),
        success: function (result) {
            $("#tableControl").html(result);
            $("#divLoading").hide();
        }
    });
}

This works fine. However, there is one specific edge-case where I can't get this to work properly.

Essentially, this project uses a plugin named EEPlus ( http://epplus.codeplex.com/ ) in order to export data into an XLS file. It's very practical for the user because they simply click on the button, and there's no redirection involved; when the file is done, the user is prompted to download it by the browser itself.

Essentially, my export method does something like this:

public void ExportListUsingEPPlus(string filter, string type)
{
    // A boat load of data processing and formatting that isn't relevant here
    // Once the work is done:
    // Write in an Excel file
    using (var memoryStream = new MemoryStream())
    {
        Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        Response.AddHeader("content-disposition", $"attachment;  filename={filename}.xlsx");
        excel.SaveAs(memoryStream);
        memoryStream.WriteTo(Response.OutputStream);
        Response.Flush();
        Response.End();
    }
}

You will notice this method doesn't return anything. It doesn't need to; in the View itself, it is called like this:

<li class="separator"><input value="Export xls" class="add" name="btn_submit" id="btn_excel" type="button" onClick="location.href='@Url.Action("ExportListUsingEPPlus", "Article", new { filter = @ViewBag.CurrentFilter, type="TEST"})'"></li>

Which is okay... except that if I try to use a loading screen for this, because exporting data can take a long while:

function exportWithLoadingScreen()
{
    $("#divLoading").show();
    $.ajax({
        contentType: 'application/json; charset=utf-8',
        url: '@Url.Action("ExportListUsingEPPlus", "Article", new { filter = @ViewBag.CurrentFilter, type = "TEST" })',
        type: "POST"
    }).complete(function (result) { $("#divLoading").hide();});
}

Ajax :

  • Doesn't proc a "success" event.

  • Doesn't proc a "failure" event.

  • Procs a "complete" event... but, of course, without location.href = '...', it doesn't actually do anything (the file is created in memory but the user is never prompted to download it).

  • If I try to use the same thing but caring about location.href, it procs the "complete" event far too early, possibly because it only cares when the redirection is complete, NOT when the method is done!

I really don't know what else I could try at this point, but it's so important to show a loading screen for this, because it really can take a long while.

Any ideas as to what else I could do? I'd appreciate it a lot!

EDIT: I'll be more precise and concise. This:

function exportWithLoadingScreen() {
    $("#divLoading").show();
    location.href = '@Url.Action("ExportListUsingEPPlus", "Article", new { filter = @ViewBag.CurrentFilter, type = "TEST" })';
    $("#divLoading").hide();

}

Doesn't work, because all actions are simultaneous, so I have to use ajax. But this:

function exportWithLoadingScreen() {
    $("#divLoading").show();
    $.ajax({
        contentType: 'application/json; charset=utf-8',
        url: '@Url.Action("ExportListUsingEPPlus", "Article", new { filter = @ViewBag.CurrentFilter, type = "TEST" })',
        type: "POST"
    }).complete(function (result) { $("#divLoading").hide(); })
};

Doesn't work either, because location.href is NOT executed (=> user is not prompted for download). But THIS:

function exportWithLoadingScreen() {
    $("#divLoading").show();
    $.ajax({
        contentType: 'application/json; charset=utf-8',
        url: '@Url.Action("ExportListUsingEPPlus", "Article", new { filter = @ViewBag.CurrentFilter, type = "TEST" })',
        type: "POST"
    }).complete(function (result) { window.location.assign(result);})
};

Doesn't work, because the returned data is completely wrong (server error), because the ExportListUsingEPPlus method doesn't return anything.

EDIT EDIT: Edited question's title to refocus the question.

I think the confusion is made by the fact that you want to use an Ajax call, but also need to redirect the page.

Ajax is used to request data from the server back to the current page so that you can update the current page with the new data.

A redirect abandons the current page and replaces it with a new one entirely.

Here is another answer that explains it, with something that can simulate an Ajax request - but it still isn't an Ajax request if it is redirecting...

https://stackoverflow.com/a/9970672/4619012

You can get help from calling ajax events. Find it here https://api.jquery.com/Ajax_Events/

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