In my Blazor app I am making an API call to a back end server that could take some time. I need to display feedback to the user, a wait cursor or a "spinner" image. How is this done in Blazor?
I have tried using CSS and turning the CSS on and off but the page is not refreshed until the call is completed. Any suggestions would be greatly appreciated.
@functions { UserModel userModel = new UserModel(); Response response = new Response(); string errorCss = "errorOff"; string cursorCSS = "cursorSpinOff"; protected void Submit() { //Show Sending... cursorCSS = ""; this.StateHasChanged(); response = Service.Post(userModel); if (response.Errors.Any()) { errorCss = "errorOn"; } //turn sending off cursorCSS = "cursorSpinOff"; this.StateHasChanged(); } }
Because Blazor Server apps use pre-rendering the spinner will not appear, to show the spinner the long operation must be done in OnAfterRender.
Now run the application , you should see a spinner ,when application will make http calls. We can show that spinner from other components as well when ever we need to show, we just has to inject SpinnerService and call Show () and Hide () method to show and hide spinner respectively. Feel free to comment and suggests changes . Happy Coding!
Blazor will update the UI as soon as the render engine gets to run on its Thread again. Much like any other UI framework all UI operations have to be done on the main thread. But your events are also running (initially) on that same thread, blocking the renderer. To resolve that, make sure your events are async by returning async Task.
Blazor will (conceptually) call StateHasChanged () after initialization and before and after events. That means you usually don't need to call it, only when your method has several distinct steps and you want to update the UI in the middle do you need to call it.
await Task.Delay(1)
or await Task.Yield();
to flush changesprivate 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.
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; }
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(); } }
Learn more about how to write nice spinner you can learn from open source project BlazorPro.Spinkit, it contains clever samples.
See Henk Holterman's answer with blazor internals explanation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With