Skip to main content

DHTMLX Kanban. Lazy loading tasks per column example

Boards with thousands of tasks across many columns can be slow to load if all data is fetched at once. Loading cards per column, fetching only the expanded column's cards and deferring the rest, dramatically improves initial load time.

Live example

const board = new kanban.Kanban("#root", {});

const url = "https://master--kanban-go--dev.webix.io";

class MyRestDataProvider extends kanban.RestDataProvider {
    getColumnCards(id) {
        return this.send("cards/column/" + id, "GET");
    }
} 

const restProvider = new MyRestDataProvider(url);
const readyCols = [1];

Promise.all([
    restProvider.getColumns(),
    restProvider.getColumnCards(1),
]).then(([a, b]) => {
    const columns = a.map(col => {
        if (col.id != 1) col.collapsed = true;
        return col;
    });
    const cards = b;  
    board.parse({cards, columns});
});

board.api.setNext(restProvider);

board.api.on("update-column", col => {
    if (!col.column.collapsed && readyCols.indexOf(col.id) == -1) {
        restProvider.getColumnCards(col.id).then(columnCards => {
            columnCards.forEach(card => {
                board.api.exec("add-card", {
                    skipProvider: true,
                    card,
                    select: false,
                });
            });
        });
        readyCols.push(col.id);
    }
});
<!-- component container -->
<div id="root" style="height: 100%;"></div>

The code extends RestDataProvider with a custom getColumnCards(id) method. On initial load, only columns and the first column's cards are fetched. All other columns start collapsed. When a user expands a column (update-column event with collapsed: false), the code checks if that column's cards have been loaded (tracked in readyCols). If not, it fetches them via getColumnCards and adds each card using api.exec("add-card", { skipProvider: true }). The skipProvider: true flag prevents re-sending these cards to the backend.

Solution overview

  1. Extend RestDataProvider with a getColumnCards(id) method
  2. Load columns and only the first column's cards on initialization
  3. Set all other columns to collapsed: true
  4. Listen to update-column. When a column is expanded, fetch and add its cards
  5. Track loaded columns in an array to avoid duplicate fetches

Key points

  • skipProvider: true prevents backend writes: Cards loaded from the backend should not be sent back. This flag skips the setNext pipeline
  • Custom provider method: RestDataProvider doesn't have getColumnCards built-in. You extend the class and add the endpoint
  • readyCols prevents refetching: Without tracking which columns are loaded, expanding/collapsing would fetch the same cards multiple times
  • Initial collapsed state: Setting col.collapsed = true on all but the first column triggers lazy loading naturally through user interaction

API reference

  • RestDataProvider: Extensible REST client
  • api.exec: Triggers events programmatically with options like skipProvider
  • api.on: Subscribes to board events

Additional resources