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.