Blazor - Display wait or spinner on API call
Option 1: Using Task.Delay(1)
- Use an async method.
- Use
await Task.Delay(1)
orawait Task.Yield();
to flush changes
private async Task AsyncLongFunc() // this is an async task
{
spinning=true;
await Task.Delay(1); // flushing changes. The trick!!
LongFunc(); // non-async code
currentCount++;
spinning=false;
await Task.Delay(1); // changes are flushed again
}
Option 1 is a simple solution that runs ok but looks like a trick.
Option 2: Using Task.Run() (not for WebAssembly)
On January'2020. @Ed Charbeneau published BlazorPro.Spinkit project enclosing long processes into task to don't block the thread:
Ensure your LongOperation()
is a Task
, if it is not, enclose it into a Task
and await for it:
async Task AsyncLongOperation() // this is an async task
{
spinning=true;
await Task.Run(()=> LongOperation()); //<--here!
currentCount++;
spinning=false;
}
Effect
Spinner and server side prerendering
Because Blazor Server apps use pre-rendering the spinner will not appear, to show the spinner the long operation must be done in OnAfterRender.
Use OnAfterRenderAsync over OnInitializeAsync to avoid a delayed server-side rendering
// Don't do this
//protected override async Task OnInitializedAsync()
//{
// await LongOperation();
//}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await Task.Run(()=> LongOperation());//<--or Task.Delay(0) without Task.Run
StateHasChanged();
}
}
More samples
Learn more about how to write nice spinner you can learn from open source project BlazorPro.Spinkit, it contains clever samples.
More Info
See Henk Holterman's answer with blazor internals explanation.
C# Blazor show spinner until foreach loop is finished
Working Blazor Demo
I have created a working Blazor Fiddle which you can use as a guide here. It simulates a long running data query and displays a loading icon while running.
The main problem with your code is that the if(isLoading)
condition is inside the loop building the table. These need to be reversed by moving the if statement outside the loop. It will then correctly either show the loading icon or show the table depending on the value of isLoading
.
So instead of this logic:
loop over data {
if loading
show icon
else
show table rows
end
}
You want it to look like this:
if (loading)
show icon
else
loop over data {
show table rows
}
end
The other change I would suggest is to load your data in either OnInitializedAsync()
or OnAfterRenderAsync()
. These are both async and you can "await" your data without the need for an extraneous Dispatcher
. Be aware that Blazor server calls the initialization twice due to pre-rendering, which you probably want to avoid if you have a long running query. Yet, the solution to that is outside the scope of the question.
Blazor loading animation for API vs. EF
I'm not sure why it works the first time but Sleep() blocks the main thread and therefore the required update rendering.
//Thread.Sleep(5000);
await Task.Delay(5000);
blazor loading spinner when component is loading html/css
You need StateHasChanged for intermediate updates. Blazor applies it before and after an event, but that doesn't help you here.
<button @onclick="@DoLogic">Load</button>
async Task DoLogic()
{
edit = false; // means loading == true
StateHasChanged(); // to be sure, probably not needed
await Task.Delay(1); // allow time for the rendering
// do the actual loading
edit = true; // means loading == false
}
The trick here is await Task.Delay(1);
so your method is suspended for a bit and Blazor can update the DOM.
There is no reason for InvokeAsync here.
Why does the spinner not stop straight away and show the message pop up?
Becuase you're running updates to fields in an asynchronous method, there's a chance that when you change those values such as the message text - that the state isn't being updated on the page and the text and is not showing.
Try using await InvokeAsync(()=>StateHasChanged());
to tell the UI that it should update with new values.
Related Topics
Deserialize Collection of Interface-Instances
Write a Well Designed Async/Non-Async API
Wixsharp Debug Custom Action in Console
How to Convert This Foreach Code to Parallel.Foreach
How to Remove All Non Alphanumeric Characters from a String Except Dash
How to Parse (Big) Xml in C# Code
Does C# 8 Support the .Net Framework
Writing Large Number of Records (Bulk Insert) to Access in .Net/C#
Mocking Httpclient in Unit Tests
How to Read and Modify Ntfs Alternate Data Streams Using .Net
Using Linq to Get the Last N Elements of a Collection
Optimal Linq Query to Get a Random Sub Collection - Shuffle
How to Get .Net Core Projects to Copy Nuget References to the Build Output
Changing the User Agent of the Webbrowser Control
Using Excel Oledb to Get Sheet Names in Sheet Order
How to Run an Exe File from My C# Code
How to Overload the Square-Bracket Operator in C#
Programmatically Determine a Duration of a Locked Workstation