Add support to Virtualize.ItemsProvider for partial updates
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
Description
### Please describe the problem.
I'm trying to
1. implement caching for lazy loaded items with `ItemsProvider`
2. improve performance, when underlying service cannot provide all requested items at once, e.g. when page size is fixed.
3. implement server side grouping, where groups' children must be retrieved separately (inspired by AG Grid's server side grouping)
#### Caching problem:
```csharp
async ValueTask> GetRows(ItemsProviderRequest request)
{
//request.Count = 50;
var items = cache.GetItems(request.StartIndex, request.Count); //returns 49 items
if (items.Count < request.Count)
{
//I want to display cached items first!
var remainingItems = await dataService.GetAsync(request.StartIndex + items.Count, request.Count - items.Count)
items.AddRange(remainingItems);
}
return new ItemsProviderResult(items, totalItemsCount: 1000);
}
```
#### underlying service cannot provide requested items at once
```csharp
const int pageSize = 15; //enforced by dataService
async ValueTask> GetRows(ItemsProviderRequest request)
{
//request.Count = 50;
int firstPage = request.StartIndex / pageSize;
int lastPage = (request.StartIndex + request.Count) / pageSize;
var items = new List();
for(int page = firstPage ; page <= lastPage; page++)
{
items.AddRange(await dataService.GetAsync(page, pageSize));
//I want to display the result immediatelly without needed to wait for all pages to load
}
}
return new ItemsProviderResult(items, totalItemsCount: 1000);
}
````
#### server side grouping
```csharp
async ValueTask> GetNoded(ItemsProviderRequest request)
{
int endIndex = request.StartIndex + request.Count;
var groups = GetVisibleGroups(request.StartIndex, request.Count);
foreach(var groupNode = groups)
{
int requiredCount = Math.Min(groupNode.Count, endIndex - groupNode.startIndex + 1);
groupNode.Children = await dataService.GetAsync(groupNode.StartIndex, requiredCount),
//I want to display the children before fetch all groups
}
}
var items = GetVisibleRowNodes(groups);
return new ItemsProviderResult(items, totalItemsCount: 1000);
}
```
### Describe the solution you'd like
I will let the API design up to you, but here are some proposals
1. New `DataSource` property on `Virtualize` component, which will allow multiple callbacks whenever partial result is ready. I like the DataSource to be an interface implementation, so that I can make it stateful (e.g. add caching). It's more OOP.
2. Add callback directly to ItemsProviderRequest
```csharp
async ValueTask> GetRows(ItemsProviderRequest request)
{
var items1 = await dataService.Get(....)
request.ProvideItems(items1, request.StartIndex); ////this will render items immediatelly
var items2 = await request.ProvideItems(items2, request.StartIndex + items1.Count)
return default;
}
```
3. Invoke multiple ItemsProvider requests, until all requested items are retrieved
```csharp
async ValueTask> GetRows(ItemsProviderRequest request)
{
return new ItemsProviderResult(items, totalItemsCount: 1000)
{
IsPartial = true; //optional, can be calculated from items.Count or from ResultStartIndex
ResultStartIndex = ....;
}
}
```
### See also
https://ag-grid.com/angular-data-grid/server-side-model-datasource/#implementing-the-server-side-datasource
Contributor guide
Assessment
This issue has not been assessed yet.