Kendo Tree View父节点显示已勾选子节点数量实现问题
解决AngularJS+Kendo TreeView父节点显示子节点勾选计数的问题
我之前也遇到过类似的需求,结合Kendo TreeView的API和AngularJS的特性,给你整理一套可行的解决方案,解决你提到的两个核心问题:
一、解决模板无法访问子节点的问题
你遇到的children.view()返回空数组,本质是因为Kendo TreeView的children是HierarchicalDataSource实例,而非普通数组。如果是延迟加载的数据源,子节点只有在展开后才会被加载;即使是一次性加载,view()返回的是经过过滤/排序的视图数据,不如直接用data()方法获取原始子节点数组可靠。
我们可以通过两个事件来确保子节点数据已加载时再计算计数:
dataBound事件:TreeView初始化完成、数据源绑定后触发,用来计算所有父节点的初始勾选数。nodeExpand事件:针对延迟加载场景,节点展开后子节点加载完成,此时更新父节点的计数。
二、解决勾选状态更新时模板不重新绑定的问题
Kendo的dataItem是ObservableObject,只要我们用set()方法更新属性,就能自动触发视图变化。同时,我们需要监听check事件,在子节点勾选状态变化时,递归更新所有祖先节点的计数,并刷新节点模板。
完整实现代码
AngularJS控制器部分
angular.module('app', ['kendo.directives']) .controller('TreeViewController', function($scope) { // 模拟你的层级数据源(支持一次性加载/延迟加载) $scope.treeData = new kendo.data.HierarchicalDataSource({ data: [ { text: '系统设置', totalChildren: 4, // 预定义总子节点数(可选,避免延迟加载时显示0) children: [ { text: '用户管理', checked: false }, { text: '权限配置', checked: true }, { text: '日志查看', checked: false }, { text: '数据备份', checked: true } ] }, { text: '业务模块', totalChildren: 5, children: [ { text: '订单管理', checked: true }, { text: '商品管理', checked: true }, { text: '客户管理', checked: false }, { text: '统计报表', checked: false }, { text: '营销活动', checked: true } ] } ] }); // 核心:更新父节点的勾选计数 function updateCheckedCount(treeView, dataItem) { if (!dataItem.children) return; // 获取已加载的子节点数组 const children = dataItem.children.data(); // 计算已勾选的子节点数量 const checkedCount = children.filter(child => child.checked).length; // 用set方法更新,触发Observable的视图更新 dataItem.set('checkedCount', checkedCount); // 刷新当前父节点的模板(避免整个TreeView重绘) const node = treeView.findByUid(dataItem.uid); treeView.refreshNode(node); } // 初始化时计算所有父节点的勾选数 $scope.onDataBound = function(e) { const treeView = e.sender; treeView.element.find('.k-item').each(function() { const dataItem = treeView.dataItem(this); if (dataItem.children) updateCheckedCount(treeView, dataItem); }); }; // 延迟加载场景:节点展开后更新父节点计数 $scope.onNodeExpand = function(e) { const treeView = e.sender; updateCheckedCount(treeView, e.dataItem); }; // 勾选状态变化时,递归更新所有祖先节点的计数 $scope.onCheck = function(e) { const treeView = e.sender; let parentNode = treeView.parent(e.dataItem); // 向上遍历所有父节点,逐一更新计数 while (parentNode) { const parentDataItem = treeView.dataItem(parentNode); updateCheckedCount(treeView, parentDataItem); parentNode = treeView.parent(parentDataItem); } }; // TreeView配置项 $scope.treeOptions = { dataSource: $scope.treeData, checkboxes: { checkChildren: true // 可选:开启父节点勾选时联动子节点 }, template: function(e) { if (e.item.children) { // 优先用预定义的totalChildren,否则用当前加载的子节点数 const total = e.item.totalChildren || e.item.children.data().length; return `${e.item.text} (${e.item.checkedCount || 0}/${total}个子节点已勾选)`; } return e.item.text; }, dataBound: $scope.onDataBound, nodeExpand: $scope.onNodeExpand, check: $scope.onCheck }; });
HTML部分
<div ng-app="app" ng-controller="TreeViewController"> <div kendo-tree-view="treeView" k-options="treeOptions"></div> </div>
关键细节说明
totalChildren字段:如果你的数据源是延迟加载,建议给每个父节点预定义总子节点数,这样即使子节点未加载,父节点也能显示正确的总数量。如果是一次性加载,可以直接用e.item.children.data().length。refreshNode方法:只刷新单个父节点的模板,相比整个TreeView重绘,性能更好。- 递归更新祖先节点:如果你的TreeView是多层级结构,勾选子节点的子节点时,所有上层父节点的计数都需要更新,所以用
while循环向上遍历。
内容的提问来源于stack exchange,提问作者illwalkwithyou
相关产品推荐
相关产品推荐

