AngularJS and Kendo UI: Watchers for Grid and Tree List

When you use the Kendo UI Grid or Tree List widgets in an AngularJS application, you will probably notice that with long grids/lists or with many columns, you’ll end up having quite a few watchers created (basically one watcher per cell). Unfortunately, it is not (yet) possible to use one time binding. The AngularJS documentation recommends keeping the number of watches under 2000 in order not to hurt the application performance (because it otherwise creates a high load during digest cycles).

The reason why so many watches are created is that the Kendo UI directives compile (using $compile) all cells so that you can use angular expression and directives in you column templates.

Disclaimer: All the instructions below only make sense if you do not need two way binding in your grid or tree list rows. If you do then you actually need these watchers.

Currently, the only way to prevent this is to initialize the Kendo Grid (or Tree List) widgets in you controller instead of using the Kendo directives. i.e. replacing this:


By a simple div:

<div id="treelist"></div>

And creating the tree list (or the grid) in you controller:


Additionally, you’ll have to replace attributes you had in your HTML code when using the directive by option or additional code. In my case, I had to move k-auto-bind to the auto-bind property in the options:

$scope.treelistKendoOptions = {
	autoBind: false,

Another attribute we were using is k-scope-field. This attribute defines a scope variable to which the Grid or Tree List should be bound. You can then call methods of the widget in your controller. The same can also be achieved when instantiating the widget from your controller:

$scope.treelistScope = $("#treelist").data("kendoTreeList");

Of course, if you use a Grid and not a Tree List, you’d use kendoGrid instead of kendoTreeList.

Once you’ve done this, you’ll see the number of watchers has greatly reduce. But you might also see that the contents of some columns are broken. This basically happens whenever you use AngularJS expression (e.g. using some methods on the scope) in you column template e.g.:

template: "<span>{{ versionFormat(dataItem.Version) }}</span>

Since we’re not in the Angular world anymore, the templates are not compiled anymore (that’s after all that’s what we wanted to prevent). So you’ll need to add the logic you had in the template to the method defined as data source. In my example above, I’d call versionFormat for every row and replace dataItem.Version by the output value.


Leave a Reply

Your email address will not be published. Required fields are marked *