1
votes

I'm populating a tree view from a datasource provided by a service worker:

postCreate: function () {
    var self = this;
    self._loadLayerConfiguration()
        .then(function (data) {
            self.layerConfig = data;
            self._treeView = $("#LayerList").kendoTreeView({
                dataValueField: "Id",
                dataTextField: "Title",
                checkboxes: {
                    checkChildren: true
                },

                check: self._onCheck.bind(self),
                dataSource: new kendo.data.HierarchicalDataSource({ /*...*/}
                })
            });
        });
},

As you can see, the configuration is set up, so that all child elements to get checked, when a parent element is checked, which then triggers the _onCheck method.

This method is now supposed to act on every checkbox that is changing:

_onCheck: function (e) {
    var dataItem = this._treeView.data("kendoTreeView").dataItem(e.node);
    if (!dataItem.layer && dataItem.Url !== null) { //Url is null, if this is a Group layer
        //load FeatureLayer, if not loaded
        //load legend, if not loaded
        //add to map
        //omitted for brevity
    }
    dataItem.layer.setVisibility(dataItem.checked);
    this._checkChildren.call(this, dataItem);
},

the problem here is, that the onCheck event is only triggered for the node the user has directly clicked, not for all children, that are affected by it.

I have tried to recursively loop through all the children of the dataItem and trigger the check event manually, but to no avail:

_checkChildren: function (dataItem) {
    var self = this;
    if (dataItem.hasChildren) {
        var children = dataItem.children.data();
        children.forEach(function (child) {
            child.set("checked", dataItem.checked);

            //self._treeView.trigger("check", {
            //  node: self._treeView.findByUid(child.uid)
            //});
            if (child.hasChildren) {
                //recurse
                self._checkChildren.call(self, child);
            }
        });
    }
},

The effect is, that the event is raised for the directly changed checkbox in the tree view, but not its children. The children only do get checked. What is a correct way to trigger the check event for all child nodes affected by a parent node?

Please do not get irritated by the .bind() and .call() invocations. Since this kendo widget has to be implemented into a Dojo 1.10 widget, the structure tends to get a bit complex.

1

1 Answers

1
votes

That's the expected behaviour according to the documentation:

Triggered after the user has checked or unchecked a checkbox. If checkChildren is true, the event is triggered after all checked states are updated.

So the event will be triggered only once, no matter how many children was checked. What I would do in your case is to handle the event with a parser to loop through all dataItems calling the _onCheck event for each one:

check: function(e) {
    _onCheck(this.dataItem(e.node));

    $(e.node).find("li").each((i, node) => _onCheck(this.dataItem(node)));
}

_onCheck: function _onCheck(dataItem) {
    console.log(dataItem);
};

Working demo:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Kendo UI Snippet</title>

    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.1.220/styles/kendo.common.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.1.220/styles/kendo.rtl.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.1.220/styles/kendo.silver.min.css"/>
    <link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.1.220/styles/kendo.mobile.all.min.css"/>

    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://kendo.cdn.telerik.com/2019.1.220/js/kendo.all.min.js"></script>
</head>
<body>
  
<div id="treeview"></div>
<script>
  let _onCheck = function _onCheck(dataItem) {
    console.log(dataItem);
  };
  
$("#treeview").kendoTreeView({
  checkboxes: {
    checkChildren: true
  },
  dataSource: [
    { text: "foo", items: [
      { text: "bar" }
    ] }
  ],
  check: function(e) {
    _onCheck(this.dataItem(e.node));
    
    $(e.node).find("li").each((i, node) => _onCheck(this.dataItem(node)));
  }
});
</script>
</body>
</html>

Dojo