Dimitar Pechev

Dimitar Pechev

Kendo UI Scheduler - Virtual Scrolling

The Kendo UI Scheduler  widget allows the user to easily schedule, display and edit a set of appointments in a very user-friendly manner. The widget is usually quick and performant, however, when you introduce grouping with many resources that picture might change. E.g., if you try to display 200 groups even loading the Day View will take quite a while and trying to create a new event or editing an existing one will be pretty slow as well, as each change to a single event causes all others to be rendered anew. Trying to display even more resources at once, e.g., with the Week View or having a much larger set of resources, the page may even go completely unresponsive, and after a while, the browser will prompt you to kill the corresponding script. One solution to the problem is implementing virtual scrolling and rendering only a part of the resources at a time.

In this step-by-step tutorial, we’ll extend the Kendo UI Scheduler Day View to add that functionality. At the end of it, you will find a link to a complete and runnable demo of the implementation.

Work Plan

Probably the slowest operation during the scheduler initialization is rendering the events. If you have too many resources though, the DOM tree itself may become too heavy and thus slow to respond. What we could do is just render a portion of all the resources and their corresponding events at once. Then we append just beneath the scheduler a scrollbar with calculated width according to the total number of resources. And whenever the scroll event is fired, we change the displayed resources according to the scroll position. Lastly, we refresh the view so that the layout and the rendered events are updated.

As already mentioned, the focus of the tutorial is on the Day View, however, extending the other views can be done similarly.


It is important to note that we are not going to override directly any Kendo UI functionality by writing custom code in any of the functions in the provided Kendo files, but rather follow this approach and just extend the existing views. So, in a separate JavaScript file we will have the following code:

Here we are going to override some of the original day view options. The things I have already added are a name identifier for the new view and a scrollbar id that will later be used to compose and select the scroller we will shortly add. Note that all custom functions and object properties that we add to the view are prefixed with "nvs" as we don’t want any collisions between our code and any future Kendo updates.

For a simple demo of the virtual scroll, we’ll just need to override only two of the original Day View functions: the “init” function where the data manipulations will take place and the “_render” function where we will attach the new scrollbar beneath the widget. In either of the two functions, we will not be deleting any of the already present code, and we will just add some custom code to achieve the desired functionality. So, go ahead and copy these two functions from the kendo.scheduler.dayview.js file.

Resources Management

The first thing we need to do is to declare a variable outside the scope of the extended view which will persist the untouched resources collection and other data that we will be using over the different initialization cycles of the view. Then we store it as part of the view object so it will be easier to mock and the rest of our custom code will not depend on an external variable. After that we start shaping up the data. Note that the “this.nvsPrepareForViewInitialization()” function has to be called after the “kendo.ui.SchedulerView.fn.init” call is done executing as all custom functions will depend on options and other configuration stored in the view object context.

Here we need to get a reference to the original set of resources before we start slicing the array to get only a small portion of them to be displayed. Notice that we directly reach for the resource collection by index. To keep the tutorial simple, we are covering a scenario with just one set of provided resources.

The “keepData” key of the “this.nvsPersistedData” object is set to true only when the virtual scroll is triggered. We will look at that code shortly. And in the scenario when it is not set to true the scroller is restored to its initial position. If it is the first time this code is being run, the scrollbar will still not have been added to the DOM, and no scroll event will be triggered.

Next, we slice through the original set of resources to take only a few, and we pass them to the resources dataSource. The “this.nvsPersistedData.resourcesStartIndex” is set when the virtual scrolling occurs. We will get to that part in a bit. If it is the first load of the scheduler, the value of this variable will be set to 0. To indicate how many resources we want to be displayed, we use the “this.options.numberOfResourcesDisplayed” value which is set in the configuration options of the scheduler, so that we avoid hard-coding here a fixed value for the number of resources we want to display.

Adding the Scrollbar

We move on to the “_render” function where we will add the scrollbar right under the widget. But first, we perform a check if it has already been added as we do not want to do that on every reinitialization cycle. It is important to place this piece of code after the stock function “this.createLayout(this._layout(dates))” is called in “_render”, as the scroller composition will depend on the layout. After all, the scrollbar width will be calculated based on the width of the header cells holding the resource names.

After the needed calculations are done, we append the scrollbar right after the scheduler. We move on to handling the resizing of the window as the scrollbar width must change accordingly.

Once that is handled, it’s time to wire up the movement of the scrollbar with the presentation of the resources.

Based on the position of the scroll we make here the needed calculations about the start index from which to slice the array of resources which is used at the beginning of this implementation. Then, we store the vertical scroll index for better UX and we set the “keepData” flag to true so that the horizontal scroller position will be retained as we reinitialize the scheduler view. Note that the event handler is wrapped in a debounce function, as the scroll event is triggered an enormous amount of times even when it’s been moved just a little. So, a small debounce timeout improves the performance especially under IE. For this tutorial I have used this jQuery Debounce extension.

The “this.nvsCalculateNextStartIndex” function sets the start index from which the original set of resources will be sliced according to the current position of the scroller. This calculation is done here as it depends on the rendered layout.

Putting the View to Work

All that’s left to do is to pass the view to the scheduler configuration and to specify the number of resources you want to be displayed along with the other typical settings (dataSource, resources, etc.). And that’s it! The scheduler will now use virtual scrolling when navigating through resources.

Known Limitations

Although these changes can dramatically improve the performance of the widget in the case of a substantial resources set, keep in mind that if each resource has too many events, it could once again result in degraded performance. The widget will still load quickly, but the scrolling will probably not be smooth. As we already mentioned, the bottleneck of the scheduler in terms of performance is the rendering of events. This issue is most noticeable in Internet Explorer as it has the slowest JavaScript engine. However, as long as you keep the events per resource down to a reasonable number this solution should work great for you.

In Conclusion

This demo covers only a basic implementation of the virtual scroll for the scheduler views. To get it ready for production it may need a lot more customizations according to the features of the widget that are being utilized and separating the UI logic (jQuery function calls) from the business logic is also desirable. To keep the tutorial as short and simple as possible, I have opted to keep the code as it is. If you run into any trouble extending this or other scheduler views beyond the proposed implementation, feel free to contact our team for assistance.


  • Check out the full source code of the tutorial on GitHub.
  • You can also try out the demo directly on RawGit.

Need consulting on this topic?

Yes No