How to implement grouping (expandable groups) with Virtualize component in Blazor?

378 Views Asked by At

I have this basic virtualized list where I load items using ItemsProvider:

<Virtualize @ref="_listbox" ItemsProvider="ProvideItems">
    <ItemContent>
        <div @key="context"
             class="[email protected]">
             @context.Label
        </div>
    </ItemContent>             
</Virtualize>

private async ValueTask<ItemsProviderResult<Item>> ProvideItems(ItemsProviderRequest request)
{
    using var db = _dbContextFactory.CreateDbContext();
    var query = db.Items
        .GroupBy(e => e.Category)
        .OrderByDescending(e => e.Key)
        .Select((group, index) => new Item
        {
           Label = group.Key, 
           Count = group.Count(),
           Index = index,
        });

    if (_totalCount == null)
    {
        _totalCount = await query.CountAsync(request.CancellationToken);
    }
    var items = await query.Skip(request.StartIndex)
        .Take(request.Count)
        .ToArrayAsync();
    return new ItemsProviderResult<Item>(items, _totalCount.GetValueOrDefault());
}


class ItemModel
{
   int Index {get; set; }
   string Label {get; set;}
   int Count {get; set;}
   // int Level {get; set;} // 0 means root
   // List<ItemModel> Children {get; set;}
}

When user click and item, it should be expanded.

How do I make the items expandable while loading children on demand?

It's non trivial exercise, maybe somebody has already done that. The component should probably track the expanded items, in order to calculate what items should be provided as user scrolls.

1

There are 1 best solutions below

0
Grandizer On

I realize I am very late to the party here (nearly a year, but no one answered you and I hate that for me) but I figured this out and thought I would share. I have a "tree-like" situation that I render in many rows of in a table where there is collapsing and expanding of parent rows if the users chooses to. I have an IsVisible bool on my object that gets swapped for the children based on the IsExpanded bool which is triggered with a checkbox.

Then in my ItemsProvider I simply do a linq query and filter on the IsVisible property before returning the ItemsProviderResult.

public async ValueTask<ItemsProviderResult<PerformanceClaimMeasurementGridViewModel>> LoadMeasurements(ItemsProviderRequest request) {
  var result = AllMeasurements
    .Where(x => x.IsVisible == true);

  return new ItemsProviderResult<PerformanceClaimMeasurementGridViewModel>(
    result
      .Skip(request.StartIndex)
      .Take(request.Count),
      result.Count()
  );
}