0

I have a page that loads a list of items in C# Blazor. I am trying to figure out a way that a spinner shows until my foreach loop has itereated all list items. This is my current code:

            @foreach (var f in FlyersState.Value.Flyers)
            {
                @if (isLoading)
                {
                    <div class="spinner"></div>
                }
                else
                {
                    <tr>
                        <td class="clickable" @onclick="()=>OpenFlyerDetails(f)">
                            @f.DealNo
                            <a href="flyers/@(f.Id)" target="_blank"><i class="fas fa-external-link-alt"></i></a>
                        </td>
                        <td>@f.Range</td>
                        <td>@f.Id</td>
                        <td>
                            <a class=" float-right" href="" data-target="#flyerModal" data-toggle="modal" @onclick="(() => EditFlyer(f))">
                                <i class="fas fa-edit"></i>
                            </a>
                        </td>
                        <td>
                            <a class=" float-right" href="" data-target="#confirmModal" data-toggle="modal" @onclick="(() => ShowDeleteConfirmAtionDialog(f))">
                                <i class="far fa-trash-alt"></i>
                            </a>
                        </td>
                    </tr>
                }

            }

and this is how my page is initialized:

    private Flyer selectedFlyer => FlyersState.Value.SelectedFlyer;
    private bool isLoading = true;

    Flyer flyer = new Flyer();

    protected override void OnInitialized()
    {

        base.OnInitialized();
        Dispatcher.Dispatch(new LoadFlyersAction());
        
    }

The problem I am running into is I am unsure of how to turn isLoading to false when the loop is done iterating my table. Any help would be appreciated.

Adil15
  • 405
  • 1
  • 5
  • 15
  • 2
    Why are you putting the spinner on each loop of the for? How do you iterate through the loop if you don't have the loop data? Where do you set `isLoading` to false? Does `Dispatcher.Dispatch(new LoadFlyersAction());` load all the data? There's too much missing here for an answer to be anything but guesswork. – MrC aka Shaun Curtis Apr 08 '22 at 15:51
  • Move data retrieving to `OnAfterRenderAsync`, take a look: https://stackoverflow.com/a/56675814/842935 – dani herrera Apr 08 '22 at 18:11
  • Nothing in your render loop should take so long that you need a spinner. Unless your Dispatcher is bringing in items by carrier pigeon, your `foreach` loop will take about a microsecond to execute. The only thing you MIGHT actually need to wait for in this way is high-data transfer actions: encoding an .mp3, uploading a file, etc. – Bennyboy1973 Apr 08 '22 at 20:29

2 Answers2

1

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.

Yogi
  • 6,241
  • 3
  • 24
  • 30
0

I'd do it this way:

<div id="spinner" class="@(spinner-state)">

@foreach (var f in FlyersState.Value.Flyers)
            {
                @if (isLoading)
                {
                    <div class="spinner"></div>
                }
                else
                {
                    <tr>
                        <td class="clickable" @onclick="()=>OpenFlyerDetails(f)">
                            @f.DealNo
                            <a href="flyers/@(f.Id)" target="_blank"><i class="fas fa-external-link-alt"></i></a>
                        </td>
                        <td>@f.Range</td>
                        <td>@f.Id</td>
                        <td>
                            <a class=" float-right" href="" data-target="#flyerModal" data-toggle="modal" @onclick="(() => EditFlyer(f))">
                                <i class="fas fa-edit"></i>
                            </a>
                        </td>
                        <td>
                            <a class=" float-right" href="" data-target="#confirmModal" data-toggle="modal" @onclick="(() => ShowDeleteConfirmAtionDialog(f))">
                                <i class="far fa-trash-alt"></i>
                            </a>
                        </td>
                    </tr>
                }

            }

And then, in the code

private string spinner-state = "show-spinner";

private Flyer selectedFlyer => FlyersState.Value.SelectedFlyer;
private bool isLoading = true;

Flyer flyer = new Flyer();

protected override void OnInitialized()
{

    base.OnInitialized();
    Dispatcher.ShutdownStarted += HideSpinner();
    Dispatcher.Dispatch(new LoadFlyersAction());
    
}

void HideSpinner(object sender, DispatcherShutdownEventArgs e)
{
     spinner-state = "hide-spinner";
}
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 09 '22 at 00:13
  • How is it unclear? I just rewrote the two blocks of code from the original post. The differences between the two demonstrate the fix? Was it reviewed by a robot? – cantcodewontcode Apr 10 '22 at 14:18