Virtual scrolling in ASP.NET MVC Grid component
6 Dec 202415 minutes to read
The virtual scrolling feature in the Grid allows you to efficiently handle and display a large amount of data without experiencing any performance degradation. It optimizes the rendering process by loading only the visible rows in the Grid viewport, rather than rendering the entire dataset at once. This is particularly useful when dealing with datasets that contain thousands of records.
Row virtualization
Row virtualization is a feature in the Syncfusion® Grid that allows you to load and render rows only in the content viewport. It provides an alternative way of paging where data is loaded dynamically while scrolling vertically, rather than loading all the data at once. This is particularly useful when dealing with large datasets, as it improves the performance and reduces the initial load time.
To set up row virtualization, you need to define the EnableVirtualization property as true and specify the content height using the Height property in the Grid configuration.
The number of records displayed in the Grid is implicitly determined by the height of the content area. Additionally, you have an option to explicitly define the visible number of records using the PageSettings.PageSize property. The loaded data will be cached and reused when needed in the future.
The following example enable row virtualization using EnableVirtualization
property.
@Html.EJS().Grid("grid").DataSource((IEnumerable<object>)ViewBag.dataSource).EnableVirtualization().Height("300").Columns(col =>
{
col.Field("TaskID").HeaderText("Task ID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).IsPrimaryKey(true).Add();
col.Field("Engineer").HeaderText("Engineer").Width("150").Add();
col.Field("Designation").HeaderText("Designation").Width("120").Format("C2").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Estimation").HeaderText("Estimation").Width("150").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Status").HeaderText("Status").Width("170").Add();
}).PageSettings(page => { page.PageSize(50); }).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true).Mode(Syncfusion.EJ2.Grids.EditMode.Normal); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render();
public IActionResult Index()
{
var data = GenerateData(5000);
ViewBag.dataSource = data;
return View();
}
private List<GridData> GenerateData(int count)
{
var names = new[] { "TOM", "Hawk", "Jon", "Chandler", "Monica", "Rachel", "Phoebe", "Gunther", "Ross", "Geller", "Joey", "Bing", "Tribbiani", "Janice", "Bong", "Perk", "Green", "Ken", "Adams" };
var hours = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var designations = new[] { "Manager", "Engineer 1", "Engineer 2", "Developer", "Tester" };
var statuses = new[] { "Completed", "Open", "In Progress", "Review", "Testing" };
var result = new List<GridData>();
var random = new Random();
for (var i = 0; i < count; i++)
{
result.Add(new GridData
{
TaskID = i + 1,
Engineer = names[random.Next(names.Length)],
Designation = designations[random.Next(designations.Length)],
Estimation = hours[random.Next(hours.Length)],
Status = statuses[random.Next(statuses.Length)]
});
}
return result;
}
public class GridData
{
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
- Row virtual scrolling is not compatible with the following feature
- Batch editing
- Detail template
- Row template
- Rowspan
- Autofill
- Hierarchy grid
- Page
- AutoFill support for Batch mode editing, so this feature is not compatible with Row Virtualization feature.
- When row virtual 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.
- The cell-based selection is not supported for row virtual scrolling.
- Using different row heights with a template column, when the template height differs for each row, is not supported.
- Group expand and collapse state will not be persisted for remote data.
- Due to the element height limitation in browsers, the maximum number of records loaded by the Grid is limited by the browser capability.
- The height of the grid content is calculated using the row height and total number of records in the data source and hence features which changes row height such as text wrapping are not supported.
-
If you want to increase the row height to accommodate the content then you can specify the row height as below to ensure all the table rows are in same height.
.e-grid .e-row { height: 2em; }
- Since data is virtualized 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, refer to the Group with paging topic.
- It is necessary to set a static height for the component or its parent container when using row virtualization. The 100% height will work only if the component height is set to 100%, and its parent container has a static height.
Column virtualization
Column virtualization feature in the Syncfusion® Grid that allows you to optimize the rendering of columns by displaying only the columns that are currently within the viewport. It allows horizontal scrolling to view additional columns. This feature is particularly useful when dealing with grids that have a large number of columns, as it helps to improve the performance and reduce the initial loading time.
To enable column virtualization, you need to set the EnableColumnVirtualization property of the Grid to true. This configuration instructs the Grid to only render the columns that are currently visible in the viewport.
The following example enable column virtualization using EnableColumnVirtualization
property.
@Html.EJS().Grid("virtualGrid").DataSource((IEnumerable<object>)ViewBag.dataSource).EnableColumnVirtualization().Height("300").Columns(col =>
{
col.Field("SNo").HeaderText("S.No").Width("140").IsPrimaryKey(true).Add();
col.Field("Field1").HeaderText("Player Name").Width("120").Add();
col.Field("Field2").HeaderText("Year").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field3").HeaderText("Stint").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field4").HeaderText("TMID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field5").HeaderText("LGID").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field6").HeaderText("GP").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field7").HeaderText("GS").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field8").HeaderText("Minutes").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field9").HeaderText("Points").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field10").HeaderText("oRebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field11").HeaderText("dRebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field12").HeaderText("Rebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field13").HeaderText("Assists").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field14").HeaderText("Steals").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field15").HeaderText("Blocks").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field16").HeaderText("Turnovers").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field17").HeaderText("PF").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field18").HeaderText("fgAttempted").Width("150").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field19").HeaderText("fgMade").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field20").HeaderText("ftAttempted").Width("150").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field21").HeaderText("ftMade").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field22").HeaderText("ThreeAttempted").Width("150").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field23").HeaderText("ThreeMade").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field24").HeaderText("PostGP").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field25").HeaderText("PostGS").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field26").HeaderText("PostMinutes").Width("120").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field27").HeaderText("PostPoints").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field28").HeaderText("PostoRebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field29").HeaderText("PostdRebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
col.Field("Field30").HeaderText("PostRebounds").Width("130").TextAlign(Syncfusion.EJ2.Grids.TextAlign.Right).Add();
}).EditSettings(edit => { edit.AllowAdding(true).AllowEditing(true).AllowDeleting(true); }).Toolbar(new List<string>() { "Add", "Edit", "Delete", "Update", "Cancel" }).Render();
public ActionResult Index()
{
ViewBag.dataSource = GenerateData(10000);
return View();
}
private List<object> GenerateData(int count)
{
var names = new[]
{
"hardire", "abramjo01", "aubucch01", "Hook", "Rumpelstiltskin", "Belle", "Emma", "Regina", "Aurora", "Elsa", "Anna",
"Snow White", "Prince Charming", "Cora", "Zelena", "August", "Mulan", "Graham", "Discord", "Will", "Robin Hood",
"Jiminy Cricket", "Henry", "Neal", "Red", "Aaran", "Aaren", "Aarez", "Aarman", "Aaron", "Aaron-James", "Aarron",
"Aaryan", "Aaryn", "Aayan", "Aazaan", "Abaan", "Abbas", "Abdallah", "Abdalroof", "Abdihakim", "Abdirahman",
"Abdisalam", "Abdul", "Abdul-Aziz", "Abdulbasir", "Abdulkadir", "Abdulkarem", "Abdulkhader", "Abdullah",
"Abdul-Majeed", "Abdulmalik", "Abdul-Rehman", "Abdur", "Abdurraheem", "Abdur-Rahman", "Abdur-Rehmaan", "Abel",
"Abhinav", "Abhisumant", "Abid", "Abir", "Abraham", "Abu", "Abubakar", "Ace", "Adain", "Adam", "Adam-James",
"Addison", "Addisson", "Adegbola", "Adegbolahan", "Aden", "Adenn", "Adie", "Adil", "Aditya", "Adnan", "Adrian",
"Adrien", "Aedan", "Aedin", "Aedyn", "Aeron", "Afonso", "Ahmad", "Ahmed", "Ahmed-Aziz", "Ahoua", "Ahtasham",
"Aiadan", "Aidan", "Aiden", "Aiden-Jack", "Aiden-Vee"
};
var random = new Random();
var data = new List<object>();
for (int i = 0; i < count; i++)
{
data.Add(new
{
SNo = i + 1,
Field1 = names[random.Next(names.Length)],
Field2 = 1967 + (i % 10),
Field3 = random.Next(200),
Field4 = random.Next(100),
Field5 = random.Next(2000),
Field6 = random.Next(1000),
Field7 = random.Next(100),
Field8 = random.Next(10),
Field9 = random.Next(10),
Field10 = random.Next(100),
Field11 = random.Next(100),
Field12 = random.Next(1000),
Field13 = random.Next(10),
Field14 = random.Next(10),
Field15 = random.Next(1000),
Field16 = random.Next(200),
Field17 = random.Next(300),
Field18 = random.Next(400),
Field19 = random.Next(500),
Field20 = random.Next(700),
Field21 = random.Next(800),
Field22 = random.Next(1000),
Field23 = random.Next(2000),
Field24 = random.Next(150),
Field25 = random.Next(1000),
Field26 = random.Next(100),
Field27 = random.Next(400),
Field28 = random.Next(600),
Field29 = random.Next(500),
Field30 = random.Next(300)
});
}
return data;
}
Column’s Width is required for column virtualization. If column’s width is not defined then Grid will consider its value as 200px.
Limitations
- While using column virtual scrolling, column width should be in pixel. Percentage values are not accepted.
- Selected column details are only retained within the viewport. When the next set of columns is loaded, the selection for previously visible columns is lost.
- The cell selection is not supported for column virtual scrolling
- The following features are compatible with column virtualization and work within the viewport:
- Column resizing
- Column reordering
- Column chooser
- Auto-fit
- Clipboard
- Column menu - Column chooser, AutofitAll
- Column virtual scrolling is not compatible with the following feature
- Grouping
- Colspan
- Batch editing
- Column with infinite scrolling
- Stacked header
- Row template
- Detail template
- Hierarchy grid
- Autofill
- Column chooser
- Page