Reputation: 3636
The QuickGrid component in Blazor takes an IQueryable object which is defered so the execution of the query is done inside the QuickGrid
How can I display a loading indicator while the QuickGrid does its magic?
@using Microsoft.AspNetCore.Components.QuickGrid
<QuickGrid Items="results" />
private IQueryable results{ get;set;}
protected override void OnInitialized()
{
results = ActivityService.GetActivities();
}
thanks
In the animation below you can see that a display message is showed for 1 sec before the quickgrid show the columns (If I add a Task.Delay(1000). but I still have to wait for the data to load without a display message
Upvotes: 0
Views: 980
Reputation: 1
I am pretty new at this, maybe this can help you out, this is the way I did it.
You can use a Modal Component, while loading, display the Modal until quickGrid
is loaded
Make the Modal component dynamic
<!-- Modal -->
<div class="modal fade show" id="exampleModalLive" tabindex="-1" aria-labelledby="exampleModalLiveLabel" aria-model="true" role="dialog" style="display:block;">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable @SizeClass">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">@Title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="OnCancelClick"></button>
</div>
<div class="modal-body">
@ChildContent
</div>
<div class="modal-footer d-flex justify-content-between">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="OnCancelClick">Close</button>
<button type="button" class="btn btn-primary" @onclick="OnActionButtonClick">@ActionButtonText</button>
</div>
</div>
</div>
</div>
<div class="modal-backdrop fade show"></div>
@code {
[Parameter, EditorRequired]
public string Title { get; set; }
[Parameter]
public ModalSize Size { get; set; } = ModalSize.Default;
[Parameter]
public string ActionButtonText { get; set; } = "Ok";
[Parameter, EditorRequired]
public RenderFragment ChildContent { get; set; }
[Parameter]
public EventCallback OnActionButtonClick { get; set; }
[Parameter]
public EventCallback OnCancelClick { get; set; }
private string SizeClass => Size switch
{
ModalSize.Small => "modal-sm",
ModalSize.Default => "",
ModalSize.Large => "modal-lg",
ModalSize.ExtraLarge => "modal-xl",
_ => ""
};
}
Call the Modal in your .Razor Page
@if(_showModal)
{
<Modal Title="String" ActionButtonText="Ok" Size="ModalSize.Large"
OnActionButtonClick="() => _showModal = false"
OnCancelClick="() => _showModal = false">
@foreach (var d in _viewingData)
{
<div class="mb-3 shadow p-3 border border-start border-sucess">
@d.Text
</div>
}
</Modal>
}
Make the AppState.ShowLoader("Loading Data Please standby")
call when OnInitialize
in Razor Component Showing the Grid
private bool _isBusy = false;
private string? _errroMessage;
private async Task TaskAsync()
{
_error = null;
_isBusy = true;
try
{
AppState.ShowLoader("Loading Data");
var apiResponse = await AuthAPI.TaskAsync(_model);
if (!apiResponse.IsSuccess)
{
_error = apiResponse.ErrorMessage;
return;
}
_showSuccessAlert = true;
}
catch (Exception ex)
{
_error = ex.Message;
}
finally
{
_isBusy = false;
AppState.HideLoader();
}
}
Create AppState
namespace NameSpace.Web.ApplicationState
{
public class AppState : IAppState
{
public string? LoadingText { get; private set; }
public event Action? OnToggleLoader;
public event Action<string>? OnShowError;
public void HideLoader()
{
LoadingText = null;
OnToggleLoader?.Invoke();
}
public void ShowLoader(string loadingText)
{
LoadingText = loadingText;
OnToggleLoader?.Invoke();
}
public void ShowError(string errorText) =>
OnShowError?.Invoke(errorText);
}
}
Create Interface from AppState
public interface IAppState
{
string? LoadingText { get; }
void ShowLoader(string loadingText);
void HideLoader();
event Action? OnToggleLoader;
void ShowError(string errorText);
}
Inject IAppState
into the Razor component
@inject IAppSate AppState
Make sure to register
builder.Services.AddSingleton<IAppState, AppState>();
Upvotes: 0
Reputation: 1
Had the exact same problem, datasource object becomes not null before entirely loading the data, resulting in delay to load with no "Loading ..." warning. This can be very annoying to the end user (thinking nothing is happening). This code did the magic for me:
private bool Busy = true;
private POCdbContext? Context { get; set; }
private List<Customer> CustomerList { get; set; } = new List<Customer>();
IQueryable<Customer>? Customers { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var task = GetData();
await task.ContinueWith(r =>
{
if (r.IsCompleted)
{
var result = r.Result;
Dispatcher.CreateDefault().InvokeAsync(() =>
{
// do stuff here
Busy = false;
// Refresh UI
InvokeAsync(StateHasChanged);
});
}
});
}
}
public async Task<List<Customer>> GetData()
{
List<Customer> customers;
Context = DbFactory.CreateDbContext();
customers = await Context.Customers.Where(x => x.Name.Contains(TitleFilter)).ToListAsync();
CustomerList = customers;
Customers = CustomerList.AsQueryable();
return customers;
}
bool Busy is the flag that controls wether QuickGrid component renders or not (standard if statement in the html section of razor page -ommited for brevity-). Page rendermode is InteractiveServer.
Adapted the original code by @Surinder Singh InThisAnswer
Hope this helps, took me a long time to find this.
UPDATE: Lol, turns out I overcomplicated things. While the above code works fine, found a way simpler solution: just add at the top of the razor page the StreamRendering attribute
@attribute [StreamRendering]
The rendering logic stays the same, an if statement that renders "loading data..." label if a property (that contains the data) is null and the data table if it is not null
Upvotes: 0
Reputation: 26
You didn't say what render mode you're using, but if you're using SSR then I think you can stream the results. Note: I haven't created a test to verify what I'm about to say, and I'm still learning this stuff myself.
That said, what I think what's happening is that...
But if you're using SSR I *think you can change that by putting this at the top of your page...
@attribute [StreamRendering]
This will cause the DOM elements rendered on the server to stream to the client as they're rendered.
The result should be that the first row should display quickly, negating the need for a loading indicator at this point. More rows are displayed as they are rendered.
Upvotes: 1
Reputation: 30177
It isn't built into DataGrid
and I don't see any simple way to detect the state of the internal iteration of the provided IQueryable
.
You will need to customize the code. I'll quote the documentation below.
QuickGrid isn't intended to replace advanced datagrid components such as those from commercial component vendors. Instead, the purpose is:
- To provide a convenient, simple, and flexible datagrid component for Blazor developers with the most common needs
- To provide a reference architecture and performance baseline for anyone building Blazor datagrid components. Feel free to build on this, or simply copy code from it.
It's not a goal to add all the features that full-blown commercial grids tend to have, for example hierarchical rows, drag-to-reorder columns, or Excel-like range selections. If you need those, continue using commercial grids or other open-source libraries. Currently we're only adding the most core grid functionality and things needed for the key fundamentals.
Upvotes: 1