Skip to content

QuickGrid ItemsProvider called first time with Count=null when using Virtualize=true #55979

@vedion

Description

@vedion

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

Hi,

Problem:
On QuickGrid when using "ItemsProvider" and "Virtualize" then ItemsProvider callback is called twice on the initial load and the first time it is called with GridItemsProviderRequest.Count=null.

Also see the example "Filtering remote data" here:
https://aspnet.github.io/quickgridsamples/filtering/

When loading there are two requests and in the first request Count is null:
https://api.fda.gov/food/enforcement.json?skip=0
https://api.fda.gov/food/enforcement.json?skip=0&limit=14

Issue:
In QuickGrid.razor the <ColumnsCollectedNotifier TGridItem="TGridItem" /> (line 12) is called before <Virtualize @ref="@_virtualizeComponent" (line 22).

The first call to the ItemsProvider callback (with Count=null) is because of the call to RefreshDataCoreAsync in the columnsFirstCollectedSubscriber setup in the constructor of QuickGrid:

public QuickGrid()
    {
        _columns = new();
        _internalGridContext = new(this);
        _currentPageItemsChanged = new(EventCallback.Factory.Create<PaginationState>(this, RefreshDataCoreAsync));
        _renderColumnHeaders = RenderColumnHeaders;
        _renderNonVirtualizedRows = RenderNonVirtualizedRows;

        // As a special case, we don't issue the first data load request until we've collected the initial set of columns
        // This is so we can apply default sort order (or any future per-column options) before loading data
        // We use EventCallbackSubscriber to safely hook this async operation into the synchronous rendering flow
        var columnsFirstCollectedSubscriber = new EventCallbackSubscriber<object?>(
            EventCallback.Factory.Create<object?>(this, RefreshDataCoreAsync));
        columnsFirstCollectedSubscriber.SubscribeOrMove(_internalGridContext.ColumnsFirstCollected);
    }

When RefreshDataCoreAsync is called the _virtualizeComponent is still null and then the GridItemsProviderRequest.Count will be null:

private async Task RefreshDataCoreAsync()
    {
        // Move into a "loading" state, cancelling any earlier-but-still-pending load
        _pendingDataLoadCancellationTokenSource?.Cancel();
        var thisLoadCts = _pendingDataLoadCancellationTokenSource = new CancellationTokenSource();

        if (_virtualizeComponent is not null)
        {
            // If we're using Virtualize, we have to go through its RefreshDataAsync API otherwise:
            // (1) It won't know to update its own internal state if the provider output has changed
            // (2) We won't know what slice of data to query for
            await _virtualizeComponent.RefreshDataAsync();
            _pendingDataLoadCancellationTokenSource = null;
        }
        else
        {
            // If we're not using Virtualize, we build and execute a request against the items provider directly
            _lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
            var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage);
            var request = new GridItemsProviderRequest<TGridItem>(
                startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token);
            var result = await ResolveItemsRequestAsync(request);
            if (!thisLoadCts.IsCancellationRequested)
            {
                _currentNonVirtualizedViewItems = result.Items;
                _ariaBodyRowCount = _currentNonVirtualizedViewItems.Count;
                Pagination?.SetTotalItemCountAsync(result.TotalItemCount);
                _pendingDataLoadCancellationTokenSource = null;
            }
        }
    }

The second call to the ItemsProvider comes from ProvideVirtualizedItems(ItemsProviderRequest request) and here the GridItemsProviderRequest.Count has a value.

Expected Behavior

When using "ItemsProvider" and "Virtualize"=true then the GridItemsProviderRequest.Count is never null.

Steps To Reproduce

Just use from code from the example "Filtering remote data":
https://aspnet.github.io/quickgridsamples/filtering/

Exceptions (if any)

No response

.NET Version

8.0.300

Anything else?

No response

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions