Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add remote operations infinite scroll section for Blazor. #922

Merged
merged 4 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 103 additions & 13 deletions doc/en/components/grids/_shared/remote-data-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,20 +87,19 @@ When requesting data, you need to utilize the `IForOfState` interface, which pro

<!-- end: Angular -->

<!-- Angular, WebComponents, React -->

## Infinite Scroll

A popular design for scenarios requiring fetching data by chunks from an end-point is the so-called infinite scroll. For data grids, it is characterized by continuous increase of the loaded data triggered by the end-user scrolling all the way to the bottom. The next paragraphs explain how you can use the available API to easily achieve infinite scrolling in `{ComponentName}`.

To implement infinite scroll, you have to fetch the data in chunks. The data that is already fetched should be stored locally and you have to determine the length of a chunk and how many chunks there are. You also have to keep a track of the last visible data row index in the grid. In this way, using the `StartIndex` and `ChunkSize` properties, you can determine if the user scrolls up and you have to show them already fetched data or scrolls down and you have to fetch more data from the end-point.

<!-- end: Angular, WebComponents, React -->

<!-- Angular -->

The first thing to do is use the `ngAfterViewInit` lifecycle hook to fetch the first chunk of the data. Setting the `TotalItemCount` property is important, as it allows the grid to size its scrollbar correctly.

The first thing to do is fetch the first chunk of the data. Setting the `TotalItemCount` property is important, as it allows the grid to size its scrollbar correctly.

<!-- Angular -->
```typescript
public ngAfterViewInit() {
this._remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
Expand All @@ -115,12 +114,36 @@ public ngAfterViewInit() {
}
```

<!-- end: Angular -->

```razor
BLAZOR CODE SNIPPET HERE
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var grid = this.grid;
grid.IsLoading = true;
double dataViewSize = 480.0 / 50.0;
this.PageSize = Convert.ToInt32(Math.Floor(dataViewSize * 1.5));
var data = await GetDataRemote(1, this.PageSize);
this.CachedData = data;
this.LocalData = this.CachedData;
grid.TotalItemCount = (this.PageSize * this.Page) + 1;
double pageCount = Math.Ceiling((double)this.TotalItems / (double)this.PageSize);
this.TotalPageCount = (int)pageCount;
grid.IsLoading = false;
StateHasChanged();
}

}
}
```

Additionally, you have to subscribe to the `DataPreLoad` output, so that you can provide the data needed by the grid when it tries to display a different chunk, rather than the currently loaded one. In the event handler, you have to determine whether to fetch new data or return data, that's already cached locally.

<!-- Angular -->

```typescript
public handlePreLoad() {
const isLastChunk = this.grid.totalItemCount ===
Expand All @@ -145,18 +168,85 @@ public handlePreLoad() {
}
}
```
<!-- end: Angular -->

```razor
BLAZOR CODE SNIPPET HERE
<IgbGrid AutoGenerate="false"
Height="480px"
Name="grid"
Id="grid"
Data="LocalData"
@ref="grid"
DataPreLoad="OnDataPreLoad">
<IgbColumn Name="ID"
Field="ProductID"
Header="ID">
</IgbColumn>

<IgbColumn Name="ProductName"
Field="ProductName"
Header="Product Name">
</IgbColumn>

<IgbColumn Name="QuantityPerUnit"
Field="QuantityPerUnit"
Header="Quantity Per Unit">
</IgbColumn>

<IgbColumn Name="UnitPrice"
Field="UnitPrice"
Header="Unit Price">
</IgbColumn>

<IgbColumn Name="OrderDate"
Field="OrderDate"
Header="Order Date">
</IgbColumn>

<IgbColumn Name="Discontinued"
Field="Discontinued"
Header="Discontinued">
</IgbColumn>

</IgbGrid>
@code {
private IgbGrid grid;
public async void OnDataPreLoad(IgbForOfStateEventArgs e)
{
int chunkSize = (int)e.Detail.ChunkSize;
int startIndex = (int)e.Detail.StartIndex;
int totalCount = (int)this.grid.TotalItemCount;

bool isLastChunk = totalCount == startIndex + chunkSize;
// when last chunk reached load another page of data
if (isLastChunk)
{
if (this.TotalPageCount == this.Page)
{
this.LocalData = this.CachedData.Skip(startIndex).Take(chunkSize).ToList();
return;
}

// add next page of remote data to cache
this.grid.IsLoading = true;
this.Page++;
var remoteData = await GetDataRemote(this.Page, this.PageSize);
this.CachedData.AddRange(remoteData);

var data = this.CachedData.Skip(startIndex).Take(chunkSize);
this.LocalData = data.ToList();
this.grid.IsLoading = false;
this.grid.TotalItemCount = Math.Min(this.Page * this.PageSize, this.TotalItems);
}
else
{
var data = this.CachedData.Skip(startIndex).Take(chunkSize).ToList();
this.LocalData = data;
}
}
}
```

<!-- end: Angular -->

<!-- WebComponents -->
<!-- end: WebComponents -->



### Infinite Scroll Demo

`sample="/{ComponentSample}/infinite-scroll", height="550", alt="{Platform} {ComponentTitle} Remote Data Operations Infinite Scroll Example"`
Expand Down
2 changes: 1 addition & 1 deletion docfx/en/components/toc.json
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@
"href": "grids/grid/paging.md"
},
{
"exclude": ["Angular", "Blazor"],
"exclude": ["Angular"],
"name": "Remote Data Operations",
"href": "grids/grid/remote-data-operations.md"
},
Expand Down
2 changes: 1 addition & 1 deletion docfx/jp/components/toc.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"href": "grids/grid/paging.md"
},
{
"exclude": ["Angular", "Blazor"],
"exclude": ["Angular"],
"name": "リモート データ操作",
"href": "grids/grid/remote-data-operations.md"
},
Expand Down
Loading