Joakim Lindberg
12 June 2024

Infinite data Grid scrolling with the new lazy loading feature

The Bryntum Version 6 release includes a new Grid feature: lazy loading. The new lazy-loading functionality improves Bryntum Grid performance […]

The Bryntum Version 6 release includes a new Grid feature: lazy loading. The new lazy-loading functionality improves Bryntum Grid performance by loading the dataset in chunks as rows scroll into view instead of loading the complete dataset at once – especially useful for applications with large datasets. Try it out in this new Grid demo. Lazy loading is also available for the Bryntum Scheduler and Scheduler Pro components.

With lazy loading enabled, the Bryntum Grid data store makes a fetch request to get the first rows of data to be rendered on page load. The number of records fetched is referred to as the “chunk size”, and it’s a configurable property of the lazyLoad feature. The store keeps track of what data has been loaded, and when a user scrolls down the grid, the next chunk of data is fetched:

In the video above, the lazy-loading data store fetches 100 rows of data at a time. The “Network status” at the top left of the toolbar displays “Loading” when data is being fetched from the server.

Let’s look at how to use this new feature; you can test the live version here on our website.

Using the lazyLoad feature

You can configure the number of records to get for each fetch request in the lazyLoad properties. The response from the server needs to match a specific format, and it’s best to include the total number of records in the database in the response.

Important considerations when using lazyLoad

The Group feature, which enables grouping multiple rows under one expandable row, is not supported when using a lazy loading store.

If you are using the lazyLoad feature with the Gantt or Scheduler, you should enable infiniteScroll so that the timeline is infinitely scrollable.

Configuration and the expected server response

The most basic configuration for using the lazyLoad feature is to add the lazyLoad property to the Grid’s store config and set it to true:

  store: {
    lazyLoad: true,
    ...

You can also configure the properties of the lazyLoad feature:

  store: {
    lazyLoad: {
      chunkSize: 100 // default value
    },
    ...

The chunkSize parameter is the number of records, or rows of data, to get for each fetch request. When a fetch request is made to get the Grid data from a server, the startIndex and count URL parameters are added to the request, where count is equal to chunkSize. The startIndex parameter is the index where the server should start reading data from the database.

The server is expected to return an object with a data property containing the records to display, with the number of records matching the quantity specified in the request’s count URL parameter. Ideally, the server response should include a total property indicating the total number of records in the database. This allows the application to determine how long the Grid will be and to stop making requests for data as the user nears the end of the records.

Event listeners

The lazyLoad feature has two event listeners:

In the next section of this post, we’ll add lazy loading to an example Grid that will use these event listeners to indicate the network state and disable adding new grid rows while data chunks are being loaded.

How to build a Bryntum Grid that uses the lazyLoad feature

We’ll show you how to add the lazyLoad feature to a Bryntum Grid using a demo app. Find the code for the demo app in the Bryntum Grid lazyLoad starter GitHub repo. The added-lazyload branch contains the code for the demo app with the lazyLoad feature added.

The demo app uses Express and serves static HTML, CSS, and JavaScript files in the /public folder. The Bryntum Grid is defined in the /public/index.js file.

The Express web server is defined in the server.js file. For simplicity, the data is stored in the sessionData variable instead of a database. The server includes API routes for CRUD operations.

The data source is in the /data/data.json file, which contains 100,000 data records. This data is read using the readFileSync method of the Node.js File System module in the getData function. The getData function is called in all the CRUD API routes.

Now let’s add the lazyLoad feature to this demo app.

Getting started

Clone the Bryntum Grid lazyLoad starter GitHub repo and follow the instructions in the README.md file to install the dependencies.

Install the Bryntum Grid component by following the instructions to access the Bryntum npm registry and then install the Grid.

Note: The lazyLoad feature was introduced in Bryntum Grid Version 6 and earlier versions are not compatible.

Start the development server with npm start. The application will be accessible at http://localhost:1337.

Adding the lazyLoad feature to the frontend code

First, configure the Grid to use the new lazyLoad feature. In the /public/index.js file, add the following lazyLoad property to the store configuration:

    lazyLoad: {
      chunkSize: 100 // default value
    },

In the features config, set group to false as grouping is not supported when using a lazy loading store:

    group: false,

In the listeners config in the store, add the following event listeners:

      lazyLoadStarted() {
        grid.widgetMap.addButton.disabled = true;
        updateNetworkValue("Loading", "blue");
      },
      lazyLoadEnded() {
        grid.widgetMap.addButton.disabled = false;
        updateNetworkValue();
      },

We disable the “Add” button and update the network status to “Loading” when data chunks are being loaded.

Updating the API endpoint to return the expected response

We need to update the "/read" API endpoint to return only the requested data chunk and the total number of records.

Replace the "/read" API GET request route definition in the server.js file with the following:

  app.get("/read", async (req, res) => {
    const { query } = req,
      { sort, filter } = query, // Params provided by the client
      startIndex = parseInt(query.startIndex),
      count = parseInt(query.count);
    let data = getData(req);
    // We got a sort param (JSON encoded array of objects)
    if (sort) {
      const decoded = JSON.parse(sort);
      // Each object has 2 properties, field (string) and ascending (boolean)
      for (const { ascending, field } of decoded) {
        sortData(req, data, field, ascending);
      }
    }
    // If no sorters, sort with default values
    else if (req.session.dataIsSorted) {
      sortData(req, data);
    }
    // We got a filter param (JSON encoded array of objects)
    if (filter) {
      const decoded = JSON.parse(filter);
      // Each filter object has 4 properties:
      // * field (string)
      // operator (=,*,>,< supported in this backend)
      // value
      // caseSensitive (boolean)
      for (const { field, operator, value, caseSensitive } of decoded) {
        const evaluator = filterEvaluators[operator], // The evaluation function matching current operator
          filterValue = caseSensitive ? value : value?.toLowerCase?.();
        data = data.filter((r) =>
          evaluator(
            caseSensitive ? r[field] : r[field]?.toLowerCase?.(),
            filterValue,
            caseSensitive
          )
        );
      }
    }
    await new Promise((resolve) => setTimeout(resolve, fakeDelay));
    // Return the expected JSON response
    res.json({
      success: true,
      total: data.length,
      data: data.slice(startIndex, startIndex + count),
    });
  });

This API route includes code for handling the sorting and filtering of data. The important changes here for lazy loading are that the returned JSON response object includes the total number of records, and the returned data only includes the data chunk requested by the Grid.

If you run your development server, you’ll see that the data in the Grid is now lazy loaded. You can see this in the Network status on the top left in the Grid toolbar or by looking in your browser dev tools Network tab.

As mentioned earlier, you can check out the live demo on our website.

Next steps

Now that you know how to add the new lazyLoad feature to a Grid, try adding a database to store the data. You can also try adding the lazyLoad feature to a Gantt or Scheduler component.

Additionally, you may want to check out our other demos:

If you have any questions or suggestions for future improvements, get in touch in our forums.

Joakim Lindberg

(MeData)

Bryntum Grid