- Virtual scrolling
- Limitations for virtual scrolling
Contact Support
Virtualization
21 Jun 202324 minutes to read
Kanban allows you to load a large amount of data without any performance degradation. This feature can be enabled by setting the enableVirtualization
property in the Kanban to true
.
Virtual scrolling
Virtual scrolling optimizes data rendering within each column when using large datasets. Only a subset of cards that are visible and about to be loaded on the screen are rendered. The number of records displayed in the Kanban is determined implicitly by the height of the Kanban area and the card height. The cardHeight
property of Kanban can be used to set the card’s height in pixel value. By default, the card height will be auto
.
When the Kanban column is scrolled, the virtual scrolling feature dynamically loads additional data on demand into view and unloads the data that is no longer visible.
<ejs-kanban id="KanbanVirtualScrolling" keyField="Status" dataSource="@ViewBag.data" enableTooltip="true" enableVirtualization="true">
<e-kanban-columns>
<e-kanban-column headerText="To Do" keyField="Open"></e-kanban-column>
<e-kanban-column headerText="In Progress" keyField="InProgress"></e-kanban-column>
<e-kanban-column headerText="Code Review" keyField="Review"></e-kanban-column>
<e-kanban-column headerText="Done" keyField="Close"></e-kanban-column>
</e-kanban-columns>
<e-kanban-cardsettings headerField="Id" contentField="Summary" selectionType="Multiple"></e-kanban-cardsettings>
<e-kanban-dialogsettings fields="@ViewBag.dialogData"></e-kanban-dialogsettings>
</ejs-kanban>
using System;
using System.Collections.Generic;
public class KanbanDataModels
{
public string Id { get; set; }
public string Title { get; set; }
public string Status { get; set; }
public string Summary { get; set; }
public string Type { get; set; }
public string Priority { get; set; }
public string Tags { get; set; }
public string StoryPoints { get; set; }
public Double Estimate { get; set; }
public string Assignee { get; set; }
public int RankId { get; set; }
public string Color { get; set; }
public List<KanbanDataModels> KanbanTasks()
{
List<KanbanDataModels> TaskDetails = new List<KanbanDataModels>();
TaskDetails.Add(new KanbanDataModels { Id = "Task 1", Title = "Task - 29001", Status = "Open", Summary = "Analyze the new requirements gathered from the customer.", Type = "Story", Priority = "Low", Tags = "Analyze,Customer", Estimate = 3.5, Assignee = "Nancy Davloio", RankId = 1, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 2", Title = "Task - 29002", Status = "InProgress", Summary = "Improve application performance", Type = "Improvement", Priority = "Normal", Tags = "Improvement", Estimate = 6, Assignee = "Andrew Fuller", RankId = 1, Color = "#7d7297" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 3", Title = "Task - 29003", Status = "Open", Summary = "Arrange a web meeting with the customer to get new requirements.", Type = "Others", Priority = "Critical", Tags = "Meeting", Estimate = 5.5, Assignee = "Janet Leverling", RankId = 2, Color = "#27AE60" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 4", Title = "Task - 29004", Status = "InProgress", Summary = "Fix the issues reported in the IE browser.", Type = "Bug", Priority = "Release Breaker", Tags = "IE", Estimate = 2.5, Assignee = "Janet Leverling", RankId = 2, Color = "#cc0000" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 5", Title = "Task - 29005", Status = "Review", Summary = "Fix the issues reported by the customer.", Type = "Bug", Priority = "Low", Tags = "Customer", Estimate = 3.5, Assignee = "Steven walker", RankId = 1, Color = "#cc0000" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 6", Title = "Task - 29007", Status = "Validate", Summary = "Validate new requirements", Type = "Improvement", Priority = "Low", Tags = "Validation", Estimate = 1.5, Assignee = "Robert King", RankId = 1, Color = "#7d7297" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 7", Title = "Task - 29009", Status = "Review", Summary = "Fix the issues reported in Safari browser.", Type = "Bug", Priority = "Release Breaker", Tags = "Fix,Safari", Estimate = 1.5, Assignee = "Nancy Davloio", RankId = 2, Color = "#cc0000" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 8", Title = "Task - 29010", Status = "Close", Summary = "Test the application in the IE browser.", Type = "Story", Priority = "Low", Tags = "Review,IE", Estimate = 5.5, Assignee = "Margaret hamilt", RankId = 3, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 9", Title = "Task - 29011", Status = "Validate", Summary = "Validate the issues reported by the customer.", Type = "Story", Priority = "High", Tags = "Validation,Fix", Estimate = 1, Assignee = "Steven walker", RankId = 1, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 10", Title = "Task - 29015", Status = "Open", Summary = "Show the retrieved data from the server in grid control.", Type = "Story", Priority = "High", Tags = "Database,SQL", Estimate = 5.5, Assignee = "Margaret hamilt", RankId = 4, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 11", Title = "Task - 29016", Status = "InProgress", Summary = "Fix cannot open user’s default database SQL error.", Priority = "Critical", Type = "Bug", Tags = "Database,Sql2008", Estimate = 2.5, Assignee = "Janet Leverling", RankId = 4, Color = "#cc0000" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 12", Title = "Task - 29017", Status = "Review", Summary = "Fix the issues reported in data binding.", Type = "Story", Priority = "Normal", Tags = "Databinding", Estimate = 3.5, Assignee = "Janet Leverling", RankId = 4, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 13", Title = "Task - 29018", Status = "Close", Summary = "Analyze SQL server 2008 connection.", Type = "Story", Priority = "Release Breaker", Tags = "Grid,Sql", Estimate = 2, Assignee = "Andrew Fuller", RankId = 4, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 14", Title = "Task - 29019", Status = "Validate", Summary = "Validate databinding issues.", Type = "Story", Priority = "Low", Tags = "Validation", Estimate = 1.5, Assignee = "Margaret hamilt", RankId = 1, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 15", Title = "Task - 29020", Status = "Close", Summary = "Analyze grid control.", Type = "Story", Priority = "High", Tags = "Analyze", Estimate = 2.5, Assignee = "Margaret hamilt", RankId = 5, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 16", Title = "Task - 29021", Status = "Close", Summary = "Stored procedure for initial data binding of the grid.", Type = "Others", Priority = "Release Breaker", Tags = "Databinding", Estimate = 1.5, Assignee = "Steven walker", RankId = 6, Color = "#27AE60" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 17", Title = "Task - 29022", Status = "Close", Summary = "Analyze stored procedures.", Type = "Story", Priority = "Release Breaker", Tags = "Procedures", Estimate = 5.5, Assignee = "Janet Leverling", RankId = 7, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 18", Title = "Task - 29023", Status = "Validate", Summary = "Validate editing issues.", Type = "Story", Priority = "Critical", Tags = "Editing", Estimate = 1, Assignee = "Nancy Davloio", RankId = 1, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 19", Title = "Task - 29024", Status = "Review", Summary = "Test editing functionality.", Type = "Story", Priority = "Normal", Tags = "Editing,Test", Estimate = 0.5, Assignee = "Nancy Davloio", RankId = 5, Color = "#8b447a" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 20", Title = "Task - 29025", Status = "Open", Summary = "Enhance editing functionality.", Type = "Improvement", Priority = "Low", Tags = "Editing", Estimate = 3.5, Assignee = "Andrew Fuller", RankId = 5, Color = "#7d7297" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 21", Title = "Task - 29026", Status = "InProgress", Summary = "Improve the performance of the editing functionality.", Type = "Epic", Priority = "High", Tags = "Performance", Estimate = 6, Assignee = "Nancy Davloio", RankId = 5, Color = "#6d7492" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 22", Title = "Task - 29027", Status = "Open", Summary = "Arrange web meeting with the customer to show editing demo.", Type = "Others", Priority = "High", Tags = "Meeting,Editing", Estimate = 5.5, Assignee = "Steven walker", RankId = 6, Color = "#27AE60" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 23", Title = "Task - 29029", Status = "Review", Summary = "Fix the editing issues reported by the customer.", Type = "Bug", Priority = "Low", Tags = "Editing,Fix", Estimate = 3.5, Assignee = "Janet Leverling", RankId = 6, Color = "#cc0000" });
TaskDetails.Add(new KanbanDataModels { Id = "Task 24", Title = "Task - 29030", Status = "Testing", Summary = "Fix the issues reported by the customer.", Type = "Bug", Priority = "Critical", Tags = "Customer", Estimate = 3.5, Assignee = "Steven walker", RankId = 1 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 25", Title = "Task - 29031", Status = "Testing", Summary = "Fix the issues reported in Safari browser.", Type = "Bug", Priority = "Release Breaker", Tags = "Fix,Safari", Estimate = 1.5, Assignee = "Nancy Davloio", RankId = 2 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 26", Title = "Task - 29032", Status = "Testing", Summary = "Check Login page validation.", Type = "Story", Priority = "Release Breaker", Tags = "Testing", Estimate = 0.5, Assignee = "Michael Suyama", RankId = 3 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 27", Title = "Task - 29033", Status = "Testing", Summary = "Fix the issues reported in data binding.", Type = "Story", Priority = "Normal", Tags = "Databinding", Estimate = 3.5, Assignee = "Janet Leverling", RankId = 4 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 28", Title = "Task - 29034", Status = "Testing", Summary = "Test editing functionality.", Type = "Story", Priority = "Normal", Tags = "Editing,Test", Estimate = 0.5, Assignee = "Nancy Davloio", RankId = 5 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 29", Title = "Task - 29035", Status = "Testing", Summary = "Fix editing issues reported in Firefox.", Type = "Bug", Priority = "Critical", Tags = "Editing,Fix", Estimate = 1.5, Assignee = "Robert King", RankId = 7 });
TaskDetails.Add(new KanbanDataModels { Id = "Task 30", Title = "Task - 29036", Status = "Testing", Summary = "Test editing feature in the IE browser.", Type = "Story", Priority = "Normal", Tags = "Testing", Estimate = 5.5, Assignee = "Janet Leverling", RankId = 10 });
return TaskDetails;
}
public List<KanbanDataModels> VirtualScrollKanbanData()
{
List<KanbanDataModels> KanbanData = new List<KanbanDataModels>();
string[] BUG_TASKS = { "UI component not displaying images in IE browser", "Button not responding on hover action",
"Text overlapping in mobile view",
"Dropdown menu not functioning properly",
"Form validation error",
"Alignment issue in tables",
"Column not loading completely",
"Broken UI Designs",
"Font size inconsistency",
"UI element misaligned on scroll"
};
string[] FEATURE_TASKS = { "Implement new user registration flow",
"Add pagination to search results",
"Improve accessibility for visually impaired users",
"Create custom dashboard for users",
"Develop user profile editing functionality",
"Integrate with third-party API for weather data",
"Implement social media sharing for articles",
"Add support for multiple languages",
"Create onboarding tutorial for new users",
"Implement push notifications for mobile app"
};
string[] EPIC_TASKS = { "Revamp UI design for entire application",
"Develop mobile application for iOS and Android",
"Create API for integration with external systems",
"Implement machine learning algorithms for personalized recommendations",
"Upgrade database infrastructure for scalability",
"Integrate with payment gateway for subscription model",
"Develop chatbot for customer support",
"Implement real-time collaboration features for team projects",
"Create analytics dashboard for administrators",
"Introduce gamification elements to increase user engagement",
};
string[] assignee = { "Andrew Fuller", "Janet Leverling", "Steven walker", "Robert King", "Margaret hamilt", "Nancy Davloio", "Margaret Buchanan", "Laura Bergs", "Anton Fleet", "Jack Kathryn", "Martin Davolio", "Fleet Jack" };
string[] status = { "Open", "InProgress", "Review", "Close", "Testing" };
string[] priority = { "Ultra-Critical", "Critical", "High", "Normal", "Low" };
string[] types = { "Epic", "Bug", "Story" };
string[] tagsField = { "Feature", "Bug", "Enhancement", "Documentation", "Automation", "Mobile", "Web", "iOS", "Safari", "Chrome", "Firefox", "Manual Testing" };
string[] storyPoints = { "1", "2", "3", "3.5", "4", "4.5", "5", "6", "7.5", "8" };
int count = 600000;
int id = 500000;
Random rnd = new Random();
int month = rnd.Next(1, 13);
for (int a = 500000; a < count; a++) {
string typeValue = types[rnd.Next(0, 2)];
string summary = typeValue == "Bug" ? BUG_TASKS[rnd.Next(0, 8)] : typeValue == "Story" ? FEATURE_TASKS[rnd.Next(0, 9)] : EPIC_TASKS[rnd.Next(0, 9)];
KanbanData.Add(new KanbanDataModels {
Id = id.ToString(),
Type = typeValue,
Priority = priority[rnd.Next(0, 4)],
Status = status[rnd.Next(0, 4)],
Assignee = assignee[rnd.Next(0, 11)],
StoryPoints = storyPoints[rnd.Next(0, 8)],
Tags = tagsField[rnd.Next(0, 11)] + "," + tagsField[rnd.Next(0, 11)],
Title = "Task " + id,
Summary = summary,
});
id++;
}
return KanbanData;
}
}
public class KanbanDialogModels
{
public string text { get; set; }
public string key { get; set; }
public string type { get; set; }
public List<KanbanDialogModels> VirtualScrollDialogCardField()
{
List<KanbanDialogModels> VirtualScrollDialogCardField = new List<KanbanDialogModels>();
VirtualScrollDialogCardField.Add(new KanbanDialogModels { text = "ID", key = "Id", type = "TextBox" });
VirtualScrollDialogCardField.Add(new KanbanDialogModels { text = "Status", key = "Status", type = "DropDown" });
VirtualScrollDialogCardField.Add(new KanbanDialogModels { key = "StoryPoints", text = "Story Points", type = "TextBox" });
VirtualScrollDialogCardField.Add(new KanbanDialogModels { key = "Summary", text = "Summary", type = "TextArea" });
return VirtualScrollDialogCardField;
}
}
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.data = new KanbanDataModels().VirtualScrollKanbanData();
ViewBag.dialogData = new KanbanDialogModels().VirtualScrollDialogCardField();
return View();
}
}
Configure the remote data service
When the remote data is configured for the dataSource
, the service method will receive an additional KanbanVirtualization
parameter to handle the initial data load for Kanban Virtualization.
To handle Kanban virtual scrolling, the server-side code needs to handle the Where
and Take
queries differently using the KanbanVirtualization
parameter. The following is the example code for handling Kanban virtualization’s initial data load using the KanbanVirtualization
parameter.
public IActionResult LoadCard([FromBody] ExtendedDataManagerRequest dm)
{
kanbanData = _context.KanbanCards.ToList();
IEnumerable<KanbanCard> DataSource = kanbanData.AsEnumerable();
DataOperations operation = new DataOperations();
// For normal kanban data load `Where` query handling.
if (dm.Where != null && dm.Where.Count > 0 && dm.KanbanVirtualization != "KanbanVirtualization")
{
dm.Where[0].value = dm.Where[0].value.ToString();
DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
}
if (dm.Skip != 0)
{
DataSource = operation.PerformSkip(DataSource, dm.Skip);
}
// For normal Kanban data load `Take` query handling.
if (dm.Take != 0 && dm.KanbanVirtualization != "KanbanVirtualization")
{
DataSource = operation.PerformTake(DataSource, dm.Take);
}
// For Kanban virtual scrolling data load `Where` and `Take` query handling.
var columnCount = new List<KeyValuePair<string, int>>();
if (dm.KanbanVirtualization == "KanbanVirtualization" && dm.Where != null && dm.Where.Count > 0 && dm.Take != 0)
{
IEnumerable<KanbanCard> currentData = new List<KanbanCard>();
List<WhereFilter> currentFilter = new List<WhereFilter>();
for (int i = 0; i < dm.Where.Count; i++)
{
dm.Where[i].value = dm.Where[i].value.ToString();
currentFilter.Add(dm.Where[i]);
var filterData = operation.PerformFiltering(DataSource, currentFilter, dm.Where[i].Operator);
columnCount.Add(new KeyValuePair<string, int>(dm.Where[i].value.ToString(), filterData.Count()));
filterData = operation.PerformTake(filterData, dm.Take);
currentData = currentData.Concat(filterData);
currentFilter.Clear();
}
DataSource = currentData;
}
// To return the data for Kanban virtual scrolling.
if (dm.KanbanVirtualization == "KanbanVirtualization") {
return Json(new { result = DataSource, count = columnCount });
}
// To return the data for Kanban virtual scrolling.
else
{
return Json(DataSource);
}
}
Limitations for virtual scrolling
- When virtualization is enabled in a Kanban board and the card height is not explicitly set, it will not default to
auto
height. Instead, a fixed height of100px
will be applied to the cards. It’s important to note that the card height should be specified in pixel values, as percentage values are not accepted. - When a card is dragged and dropped, the index position of the card will not be preserved when scrolling through the column.
- Virtualization is not supported for swimlanes in the Kanban board.