PrimeFaces如何使用selectCheckboxMenu实现TreeTable多值过滤
不需要重构、移除服务端保存的原始TreeNode结构,直接修改原始节点会导致清空过滤条件时无法恢复全量树,必须重新加载全量数据,既容易出现数据不一致问题,还会增加不必要的性能开销。
核心实现逻辑
全程保留加载完成的全量树原始根节点引用不做任何增删修改,过滤时单独生成一份过滤后的树结构绑定给TreeTable即可,具体步骤如下:
- 初始化树时单独存储全量树根节点,比如定义
private TreeNode fullTreeRoot;保存全量数据,TreeTable的value属性绑定单独的过滤后节点对象private TreeNode filteredTreeRoot;,页面初始加载时直接让filteredTreeRoot = fullTreeRoot即可展示全量树。 - 编写递归过滤方法,匹配时要同时满足两个规则:节点自身属性命中选中值则保留;节点自身不命中但存在任意层级的子节点命中,父节点也要保留(否则命中的子节点无法在树结构中展示)。参考实现代码如下:
private TreeNode buildFilteredTree(TreeNode currentNode, Set<Object> selectedFilterVals, String matchProperty) { // 复制当前节点,不修改原始节点数据 TreeNode nodeCopy = new DefaultTreeNode(currentNode.getData(), null); boolean isMatch = selectedFilterVals.contains( // 替换成你自己的业务属性取值逻辑,比如取节点对应实体的分类、状态等过滤字段 ((YourBusinessEntity)currentNode.getData()).getFilterField() ); // 递归处理所有子节点 for (TreeNode child : currentNode.getChildren()) { TreeNode filteredChild = buildFilteredTree(child, selectedFilterVals, matchProperty); if (filteredChild != null) { nodeCopy.getChildren().add(filteredChild); isMatch = true; } } // 自身匹配或存在匹配子节点则返回节点副本,否则返回null代表该分支不展示 return isMatch ? nodeCopy : null; }
- 给selectCheckboxMenu绑定值变更ajax事件,触发时执行过滤逻辑:
- 先判断后端拿到的选中值集合,如果为空(用户未选任何过滤项),直接将
filteredTreeRoot赋值为fullTreeRoot,直接展示全量数据 - 如果选中值集合不为空,从
fullTreeRoot开始调用上述递归方法,将返回的过滤后树结构赋值给filteredTreeRoot - 调用TreeTable组件的
update()方法刷新前端展示即可
- 先判断后端拿到的选中值集合,如果为空(用户未选任何过滤项),直接将
避坑提示
- 不要在原始全量树节点上做增删子节点的操作,否则清空过滤条件时被删除的节点无法恢复,只能重新查询构造全量树,额外增加开销。
- 如果使用懒加载TreeTable,递归时仅处理已经加载完成的子节点,未加载的分支直接保留,等用户手动展开节点时再按过滤规则加载对应子节点即可,不要提前触发全量树加载。
- 如果需要支持模糊匹配、跨字段匹配等复杂规则,只需要替换递归方法里的命中判断逻辑即可,整体递归框架不需要调整。
内容的提问来源于stack exchange,提问作者Antoine Clement
相关产品推荐
相关产品推荐

