2
votes

I have a small thing that I need to do. There's my problem. I open a component, and then I can click "edit" and then I need 3-4 seconds while that need html/css is shown on the page. What I'm trying to do is that when I click "edit" I set "loading = true", and when component finishes rendering that new html/css I set "loading = false". Here is a sample of what I'm trying to achieve:

if (!edit) {
   <h2>test</h2>
   @foreach (var item in items) {
      <p>Test item</p>
   }
}
else {
   <button @onclick = "() => { edit = true; }">
   <h2>test other </h2>
   <input />
   <input />
}

This is how I set loading spinner to show on page:

await InvokeAsync(() => { loading = true; });
await InvokeAsync(() => { loading = false; });

So, my question is how can I make that when a person presses edit, the spinner automatically starts spinning on the screen. I know how to do it when OnInitializedAsync, but at this specific situation, it's not being initialized, it just shows a different part of the component (but it takes 5 seconds, huge code). Is there a way?

1
Are you calling ‘StateHasChanged()’ after setting your loading property/field? - Kane
nope, don't set it. "await InvokeAsync(() => { loading = true; });" automaticaly does the job. But that's not the problem. Problem is that I don't understand lifcycle of blazor components. So no idea where to put this "loading =true" and "loading = false". Is it in OnAfterRenderAsync? How do I put the logic for this to work - Povilas Dirse
@PovilasDirse you normally place it before and after the call to load the data. Sometimes I have had to use Thread.Sleep(1) to yield for the screen to update after each time you set the loading flag. - Brian Parker
so, I would have like this: @onclick = "() => { await logic(); }". Inside "logic" method I would sleep the thread and set edit to true? - Povilas Dirse
@PovilasDirse yes before and after the data or whatever is taking the time. Inside "logic" edit = true; ThreadSleep(1); StateHasChanged(); Do your slow code ....; edit = false; StateHasChanged(); - Brian Parker

1 Answers

1
votes

You need StateHasChanged for intermediate updates. Blazor applies it before and after an event, but that doesn't help you here.

@onclick = "async () => { await DoLogic(); }"


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.