p:tree/o:tree节点内p:autoUpdate单独更新节点不生效问题求解
问题根因
- 迭代类组件(
p:tree/o:tree都属于此类)内部定义的组件ID是模板ID,实际渲染时每个节点的子组件都会自动加上节点索引前缀,比如你定义的id="personName",实际生成的客户端ID类似personTree:0:personName、personTree:1:personName,每个节点对应唯一ID。你直接在更新列表写@id(personName)或者全局触发person-change-event时,框架无法匹配到具体节点下的组件,因此不会触发渲染。 - 你在业务方法中调用
treeModel.onPostConstruct()重建整棵树属于冗余操作,你已经直接修改了Person实体的属性,只要树模型绑定正确,不需要重建整个树结构,反而会增加不必要的性能开销,还可能导致节点状态丢失。
解决方案
方案1:后端手动指定更新节点ID(推荐,性能最优)
直接在业务方法中获取需要更新的节点对应的客户端ID,加入AJAX更新列表即可:
- 去掉
p:outputPanel内部的p:autoUpdate标签 - 调整业务代码如下:
@Action public class PersonFormAction { private static final Random RANDOM = new Random(); @Inject private PersonFormViewModel viewModel; @Inject private PersonTreeModel treeModel; public void changePersonAction() { final Person selectedPerson = viewModel.getSelectedPerson(); if (selectedPerson.getState().equals("alive")) { selectedPerson.setState("dead"); } else { selectedPerson.setState("alive"); } selectedPerson.setName(selectedPerson.getName() + " " + RANDOM.nextInt(10)); // 删除冗余的树重建逻辑 // treeModel.onPostConstruct(); // 手动添加对应节点的客户端ID到更新列表,o:tree调整前缀为oTree即可 String updateId = String.format("personTree:%d:personName", selectedPerson.getDbId()); PrimeFaces.current().ajax().update(updateId); } }
如果你的dbId不是从0开始的连续值,可以遍历树的子节点找到对应Person的节点,获取其索引拼接ID即可。
方案2:带条件的autoUpdate
如果要保留事件驱动的更新模式,可以给p:autoUpdate增加条件判断,只有当前节点是被修改的节点时才生效:
<p:outputPanel layout="inline" id="personName" styleClass="person-#{person.state}"> <h:outputText value="#{person.name}"/> <p:autoUpdate on="person-change-event" disabled="#{person.dbId != personFormViewModel.selectedPerson.dbId}"/> </p:outputPanel>
触发person-change-event时,只有被选中的人员对应节点的autoUpdate会生效,其余节点的更新会被跳过,同样可以实现只更新目标节点的效果。
额外优化建议
- 命令按钮的update列表中可以删除无效的
@id(personName)配置 PersonSessionModel不要使用@ApplicationScoped,该作用域下所有用户共享同一份人员列表,会出现数据冲突,根据业务场景改为@SessionScoped或@ViewScoped更合理。
内容的提问来源于stack exchange,提问作者MaNa
相关产品推荐
相关产品推荐

