Virtualization in EJ2 TypeScript Kanban control

29 Aug 20239 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 cards’ 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.

import { Kanban } from '@syncfusion/ej2-kanban';
import { generateKanbanDataVirtualScrollData } from './datasource.ts';

let kanbanObj: Kanban = new Kanban({
    enableVirtualization: true, // To enable virtual scrolling feature.
    dataSource: generateKanbanDataVirtualScrollData(),
    keyField: 'Status',
    enableTooltip: true,
    columns: [
        { headerText: 'To Do', keyField: 'Open' },
        { headerText: 'In Progress', keyField: 'InProgress' },
        { headerText: 'Code Review', keyField: 'Review'},
        { headerText: 'Done', keyField: 'Close' }
    ],
    cardSettings: {
        headerField: 'Id',
        contentField: 'Summary',
        selectionType: 'Multiple'
    },
    dialogSettings : {
        fields: [
            {key: 'Id', text: 'ID', type: 'TextBox'},
            {key: 'Status', text: 'Status', type: 'DropDown'},
            {key: 'StoryPoints', text: 'Story Points', type: 'Numeric' },
            {key: 'Summary', text: 'Summary', type: 'TextArea'}
        ]
    }
});
kanbanObj.appendTo('#Kanban');
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Kanban Local Data</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Kanban Local Data" />
    <meta name="author" content="Syncfusion" />
    <link href="index.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-buttons/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-inputs/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-dropdowns/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-layouts/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-navigations/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-popups/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-kanban/styles/material.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js" type="text/javascript"></script>
    <script src="systemjs.config.js" type="text/javascript"></script>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='loader'>LOADING....</div>
    <div id='container'>
        <div class="content-wrapper">
            <div id="Kanban"></div>
        </div>
    </div>
</body>

</html>

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 of 100px 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.