Search code examples
c#asp.net-corerazorspinnerrazor-pages

Razor Page show spinner on while waiting for OnGetAsync


I am trying to show a spinner while my OnGetAsync is processing.

I have a form that looks something like this:

<form method="get">
    <div class="row">
        <button type="submit" class="btn btn-primary" name="action" value="1">1</button>
        <button type="submit" class="btn btn-primary" name="action" value="2">2</button>
    </div>
</form>

I have been able to show my spinner when pressing a button by adding an onclick that triggers the jquery .show() method. However, I then have no good way to stop it when my OnGetAsync returns.

What is the correct way to handle something like this?


Updated example:

<form method="get">
    <div class="row">
        <button id="pdfbutton" type="submit" class="btn btn-primary" name="action" value="PDF">PDF</button> *@
        <span id="spinner" class="loader" style="display:none;"></span>
    </div>
</form>


@section Scripts{
    <script>
        $("#pdfbutton").click(function(){
            $("#spinner").show();
        });
    </script>
}

public class IndexModel : PageModel
{
    public Task<IActionResult> OnGetAsync(string? action)
    {
        if (action == "PDF") {
            var file = await File.ReadAllBytesAsync(<path to some pdf file>);
            return File(file, "application/pdf", "file.pdf");
        }
        return Page();
    }
}

Solution

  • in razor project, c# can't run in the client, here's another similar issue which mentioned it, so we'd better to control the loading to display or not. Since you didn't provide a minimal sample, so I have a test in my side with code below:

    <form method="get">
        <div class="row">
            @* <button type="submit" class="btn btn-primary" name="action" value="1">1</button>
            <button type="submit" class="btn btn-primary" name="action" value="2">2</button> *@
            <button id="showImg">show loading</button>
        </div>
    </form>
    
    <div id="loadImg" style="display:none;">
        <img style="width:50px;height:50px;" src="~/loading.gif" />
    </div>
    
    @section Scripts{
        <script>
            $("#showImg").click(function(){
                $("#loadImg").show();
            });
        </script>
    }
    
    public class IndexModel : PageModel
    {
        public IActionResult OnGet()
        {
            return Page();
        }
    }
    

    And here's the test result.

    enter image description here

    Since I had a return Page() in the method, each time the onGet is called, the whole page would reload so that my loading icon would become the default invisible. If we want to reload part of the page like what ajax does, then all these should be controlled by js. For example, in the onclick event, we might send an ajax request, before sending the request, we could call the .show() method to display the loading icon, and inside the callback method, we could call .hide() method make it invisible.

    =================== UPDATE =================

    The problem we are facing now it find a trigger to let the page know the form submission is completed, and we don't have such a callback method indeed, so I found a workaround which worked in this scenario.

    $([window, top.window]).blur(function () {
        $("#loadImg").hide();
    });
    

    enter image description here

    By the way, I tried to return File along with the page so that the page would reload and hide the loading icon, but it proved to be impossible. I also tried to define a variable but razor pages is not like razor component so that we couldn't monitor the variable to check if the submission is completed. Another way I think could be possible is that we submit the form/download the file via javascript manually so that we could control the icon to show or not in the file-download progress. For example, we can have code like this, this makes us not able to hide the icon whenever the file returned, but I trust if we are always trying to return a small file, then 1~2 seconds is enough.

    $("#showImg2").click(function(){
        $("#loadImg").show();
        downloadUrl("/?action=PDF");
        setTimeout(hideImg, 2000);
    });
    
    function hideImg() { 
        $("#loadImg").hide();
    }
    

    enter image description here