How can I show a loading image before the MVC call has returned the model?

2020-02-15 c# asp.net-mvc

I have an HTML button in the file generateReport.cshtml, that opens a new tab to display the report:

<div>
   <a id="btnPreviewPDF" class="btn" href="#" title="Preview Report" target="_blank">Preview</a>
</div>

This kicks off an MVC GET in reportController.cs that creates the model to be used by the html that renders the report:

[GET("PreviewPdf/{id:int}/{reportDate}")]
        public virtual ActionResult PreviewReport(int id, string reportDate)
        {            
            var helper = new ReportHelper(client);
            var model = helper.GenerateViewModelForPreviewReport(id, reportDate);

            return View(model);
        }

Then the above model is used in viewReport.cshtml as a model to display the data, for example:

@model Reports.ReportHelper

<div class="sub-header-text primary-orange text-bold">
   Summary: @Model.ReportDate.ToString("MMMM") @Model.ReportDate.ToString("yyyy")
</div>

Waiting for the PreviewReport to return in the GET of reportController.cs can take 30+ seconds to run so I would like to display a loading image/gif on the new tab that's created by clicking the 'Preview' button. Since this GET command is running before the HTML code in viewReport.cshtml I have not been able to figure out a way to do this. I would like to display a loading image on that new tab and prevent the browser from throwing a message thinking that the page is not responding.

Answers

In the first response return loading string/image + a script which send an ajax request to load the report, then in response to the ajax request, return the report content.

This way the page will be shown immediately and in the contents, shows a loading, then after a few seconds when the ajax request received the response, the page content will be updated.

Controller

In the controller, check if it's ajax request, return the partial view which contains the report. Otherwise, return the view which just contains loading and the ajax script:

public ActionResult Report()
{
    if (Request.IsAjaxRequest())
    {
        //Delay just for demo purpose
        System.Threading.Thread.Sleep(5000);
        return PartialView("_Report");
    }
    else
        return View("Report");
}

Report.cshtml

Use this view just to show loading and send the ajax request:

@{ ViewBag.Title = "Report"; }

<div id="content">
    Loading ...
</div>

@section Scripts
{
    <script>
        $(function () {
            $.ajax({
                url: "/Home/Report",
                success: function (data) { $('#content').html(data); },
                error: function () { alert(error); },
                cache: false,
                type: 'GET'
            });
        });
    </script>
}

_Report.cshtml

Use this partial view to shows actual report content:

Actual report content

Related