Infinite scroll in Blazor DataGrid
28 Apr 202519 minutes to read
The infinite scrolling feature in the Syncfusion Blazor DataGrid is a powerful tool for seamlessly handling extensive data sets without compromising Grid performance. It operates on a “load-on-demand” concept, ensuring that data is fetched only when needed. In the default infinite scrolling mode, a new block of data is loaded each time the scrollbar reaches the end of the vertical scroller. This approach significantly enhances the user experience when working with large data collections in the Blazor Grid.
In this mode, a block of data accumulates every time the scrollbar reaches the end of the scroller. To clarify, in this context, a block represents the PageSize of the Grid. If the PageSize
is not explicitly specified, the Grid will automatically calculate it based on the Grid viewport height and row height.
To enable infinite scrolling, you need to define EnableInfiniteScrolling as true and set the content height using the Height property.
- In this feature, the Grid will not initiate a new data request when revisiting the same page.
- The
Height
property must be specified when enablingEnableInfiniteScrolling
.
The following is an example that demonstrates how to enable infinite scroll in the Grid:
@using Syncfusion.Blazor.Grids
<SfGrid DataSource="@TaskData" Height="300" EnableInfiniteScrolling="true">
<GridPageSettings PageSize="50"></GridPageSettings>
<GridColumns>
<GridColumn Field=@nameof(TaskDetails.TaskID) HeaderText="TaskID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Engineer) HeaderText="Engineer" Width="150"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Designation) HeaderText="Designation" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Estimation) HeaderText="Estimation" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Status) HeaderText="Status" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public List<TaskDetails> TaskData { get; set; }
protected override void OnInitialized()
{
TaskData = TaskDetails.GenerateData(5000);
}
}
public class TaskDetails
{
public static List<TaskDetails> GenerateData(int count)
{
var names = new List<string> { "TOM", "Hawk", "Jon", "Chandler", "Monica", "Rachel", "Phoebe", "Gunther", "Ross", "Geller", "Joey", "Bing", "Tribbiani", "Janice", "Bong", "Perk", "Green", "Ken", "Adams" };
var hours = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var designations = new List<string> { "Manager", "Engineer 1", "Engineer 2", "Developer", "Tester" };
var statusValues = new List<string> { "Completed", "Open", "In Progress", "Review", "Testing" };
var random = new Random();
var result = new List<TaskDetails>();
// Generate random data.
for (int i = 0; i < count; i++)
{
result.Add(new TaskDetails
{
TaskID = i + 1,
Engineer = names[random.Next(names.Count)],
Designation = designations[random.Next(designations.Count)],
Estimation = hours[random.Next(hours.Count)],
Status = statusValues[random.Next(statusValues.Count)]
});
}
return result;
}
public int TaskID { get; set; }
public string Engineer { get; set; }
public string Designation { get; set; }
public int Estimation { get; set; }
public string Status { get; set; }
}
Number of blocks rendered during initial loading
The number of blocks to be initially rendered when the Syncfusion Blazor DataGrid is loaded. Each block corresponds to a page size of the Grid, resulting in the rendering of a certain number of row elements determined by multiplying the initial block size by the page size.
You can define the initial loading page count by using the InitialBlocks property of the GridInfiniteScrollSettings class. By default, this property loads three pages during the initial rendering. Subsequently, additional data is buffered and loaded based on either the page size or the number of rows rendered within the provided height.
The following is an example of how you can use the InitialBlocks
property to set the initial loading pages based on DropDownList input:
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.DropDowns
<div style="margin-bottom:5px">
<label style="padding: 30px 2px 0 0">Select InitialBlocks count:</label>
<SfDropDownList TValue="int" TItem="Rows" Placeholder="Select count" Width="220px" DataSource="DropDownData">
<DropDownListFieldSettings Text="Text" Value="Value"></DropDownListFieldSettings>
<DropDownListEvents ValueChange="ValueChanged" TValue="int" TItem="Rows"></DropDownListEvents>
</SfDropDownList>
</div>
<SfGrid @ref="Grid" DataSource="@TaskData" Height="300" EnableInfiniteScrolling="true">
<GridPageSettings PageSize="50"></GridPageSettings>
<GridInfiniteScrollSettings InitialBlocks="@InitialBlockValue"></GridInfiniteScrollSettings>
<GridColumns>
<GridColumn Field=@nameof(TaskDetails.TaskID) HeaderText="TaskID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Engineer) HeaderText="Engineer" Width="150"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Designation) HeaderText="Designation" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Estimation) HeaderText="Estimation" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Status) HeaderText="Status" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code {
public SfGrid<TaskDetails> Grid { get; set; }
public List<TaskDetails> TaskData { get; set; }
protected override void OnInitialized()
{
TaskData = TaskDetails.GenerateData(1000);
}
public int InitialBlockValue { get; set; }
public class Rows
{
public int Text { get; set; }
public int Value { get; set; }
}
private List<Rows> DropDownData = new List<Rows>
{
new Rows() { Text = 1, Value = 1 },
new Rows() { Text = 2, Value = 2 },
new Rows() { Text = 3, Value = 3 },
new Rows() { Text = 4, Value = 4 },
new Rows() { Text = 5, Value = 5 },
new Rows() { Text = 6, Value = 6 },
new Rows() { Text = 7, Value = 7 },
};
public async Task ValueChanged(ChangeEventArgs<int, Rows> Args)
{
InitialBlockValue = Args.Value;
await Grid.Refresh();
}
}
public class TaskDetails
{
public static List<TaskDetails> GenerateData(int count)
{
var names = new List<string> { "TOM", "Hawk", "Jon", "Chandler", "Monica", "Rachel", "Phoebe", "Gunther", "Ross", "Geller", "Joey", "Bing", "Tribbiani", "Janice", "Bong", "Perk", "Green", "Ken", "Adams" };
var hours = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var designations = new List<string> { "Manager", "Engineer 1", "Engineer 2", "Developer", "Tester" };
var statusValues = new List<string> { "Completed", "Open", "In Progress", "Review", "Testing" };
var random = new Random();
var result = new List<TaskDetails>();
// Generate random data.
for (int i = 0; i < count; i++)
{
result.Add(new TaskDetails
{
TaskID = i + 1,
Engineer = names[random.Next(names.Count)],
Designation = designations[random.Next(designations.Count)],
Estimation = hours[random.Next(hours.Count)],
Status = statusValues[random.Next(statusValues.Count)]
});
}
return result;
}
public int TaskID { get; set; }
public string Engineer { get; set; }
public string Designation { get; set; }
public int Estimation { get; set; }
public string Status { get; set; }
}
Efficient data caching and DOM management in Grid cache mode
In Syncfusion Blazor DataGrid cache mode, cached data blocks are reused when revisiting them, reducing the need for frequent data requests while navigating the same block. This mode also manages DOM row elements based on the GridInfiniteScrollSettings.MaximumBlocks count value. If this limit is exceeded, it removes a block of row elements to create new rows.
To enable cache mode, define the EnableCache property of GridInfiniteScrollSettings as true.
To configure the maximum blocks, set the MaximumBlocks
count of GridInfiniteScrollSettings
. By default, this property value is 3.
The following example demonstrates how to enable or disable cache mode in infinite scrolling of the Grid based on the Toggle Switch Button ValueChange event:
@using Syncfusion.Blazor.Grids
@using Syncfusion.Blazor.Buttons
<div style="display:flex; margin-bottom:5px">
<label> Enable or Disable Cache mode:</label>
<SfSwitch ValueChange="Change" TChecked="bool"></SfSwitch>
</div>
<SfGrid @ref="Grid" DataSource="@TaskData" Height="300" EnableVirtualization="true">
<GridPageSettings PageSize="50"></GridPageSettings>
<GridInfiniteScrollSettings EnableCache="@IsEnabled"></GridInfiniteScrollSettings>
<GridColumns>
<GridColumn Field=@nameof(TaskDetails.TaskID) HeaderText="TaskID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Engineer) HeaderText="Engineer" Width="150"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Designation) HeaderText="Designation" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Estimation) HeaderText="Estimation" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
<GridColumn Field=@nameof(TaskDetails.Status) HeaderText="Status" Width="150"></GridColumn>
</GridColumns>
</SfGrid>
@code{
public SfGrid<TaskDetails> Grid { get; set; }
public List<TaskDetails> TaskData { get; set; }
protected override void OnInitialized()
{
TaskData = TaskDetails.GenerateData(1000);
}
public bool IsEnabled { get; set; }
private void Change(Syncfusion.Blazor.Buttons.ChangeEventArgs<bool> args)
{
IsEnabled = args.Checked;
Grid.Refresh();
}
}
public class TaskDetails
{
public static List<TaskDetails> GenerateData(int count)
{
var names = new List<string> { "TOM", "Hawk", "Jon", "Chandler", "Monica", "Rachel", "Phoebe", "Gunther", "Ross", "Geller", "Joey", "Bing", "Tribbiani", "Janice", "Bong", "Perk", "Green", "Ken", "Adams" };
var hours = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var designations = new List<string> { "Manager", "Engineer 1", "Engineer 2", "Developer", "Tester" };
var statusValues = new List<string> { "Completed", "Open", "In Progress", "Review", "Testing" };
var random = new Random();
var result = new List<TaskDetails>();
// Generate random data.
for (int i = 0; i < count; i++)
{
result.Add(new TaskDetails
{
TaskID = i + 1,
Engineer = names[random.Next(names.Count)],
Designation = designations[random.Next(designations.Count)],
Estimation = hours[random.Next(hours.Count)],
Status = statusValues[random.Next(statusValues.Count)]
});
}
return result;
}
public int TaskID { get; set; }
public string Engineer { get; set; }
public string Designation { get; set; }
public int Estimation { get; set; }
public string Status { get; set; }
}
Limitations
- Due to the element height limitation in browsers, the maximum number of records loaded by the Grid is limited due to the browser capability.
- It is necessary to set a static height for the component or its parent container when using infinite scrolling. The 100% height will work only if the component height is set to 100%, and its parent container has a static height.
- The combined height of the initially loaded rows must exceed the height of the viewport.
- When infinite scrolling is activated, compatibility for copy-paste and drag-and-drop operations is limited to the data items visible in the current viewport of the Grid.
- Cell selection will not be persisted in cache mode.
- The group records cannot be collapsed in cache mode.
- Lazy load grouping with infinite scrolling does not support cache mode, and the infinite scrolling mode is exclusively applicable to parent-level caption rows in this scenario.
- In normal grouping, infinite scrolling is not supported for child items when performing expand and collapse actions on caption rows. All child items are loaded when the caption rows are expanded or collapsed in Grid.
- The aggregated information and total group items are displayed based on the current view items. To get these information regardless of the view items.
- Programmatic selection using the SelectRowsAsync and SelectRowAsync method is not supported in infinite scrolling.
- Infinite scrolling is not compatible with the following features:
- Batch editing
- Normal editing
- Row template
- Row virtual scrolling
- Detail template
- Hierarchy features
- Autofill
- Limitations of row drag and drop with infinite scrolling
- In cache mode, the Grid refreshes automatically if the content’s tr element count exceeds the cache limit of the Grid’s content after the drop action.
- When performing row drag and drop with lazy load grouping, the Grid will refresh automatically.
- In remote data, changes are applied only in the UI. They will be lost once the Grid is refreshed. To restore them, you need to update the changes in your database. By using the RowDropped event, you can send the request to the server and apply the changes in your database. After this, you need to refresh the Grid to show the updated data.