JSF嵌套ui:repeat内PrimeFaces组件更新外层组件报错
现有一段基于JSF+PrimeFaces的嵌套迭代渲染代码,初始实现如下:
<h:form id="groupsForm"> <ui:repeat value="#{groupsContainer.groups}" var="group"> <p:outptuText value="#{group.name}" /> <p:card id="group"> <ui:repeat value="#{group.users}" var="user"> <p:outputText value="#{user.name}" /> <p:commandButton value="Delete" process="@this" actionListener="#{groupsController.deleteUserFromGroup(group, user)}" update="group" /> </ui:repeat> </p:card> </ui:repeat> </h:form>
运行时删除按钮无法定位同分组下的卡片组件,抛出组件找不到异常:
org.primefaces.expression.ComponentNotFoundException: Cannot find component for expression "group" referenced from "groupsForm:j_idt42:0:j_idt73:0:j_idt102".
最初判断是嵌套<ui:repeat>的作用域限制,尝试调整组件ID、用<h:panelGroup/>包裹目标组件均未解决问题。后续缩小更新范围,不再更新整个<p:card/>组件,仅更新内层迭代的用户列表区域,调整后代码如下:
<h:form id="groupsForm"> <ui:repeat value="#{groupsContainer.groups}" var="group"> <p:outptuText value="#{group.name}" /> <p:card id="group"> <h:panelGroup id="users"> <ui:repeat value="#{group.users}" var="user"> <p:outputText value="#{user.name}" /> <p:commandButton value="Delete" process="@this" actionListener="#{groupsController.deleteUserFromGroup(group, user)}" update="users" /> </ui:repeat> </h:panelGroup> </p:card> </ui:repeat> </h:form>
调整后依然抛出同类异常,仅提示找不到的组件表达式变为users:
Cannot find component for expression "users" referenced from "groupsForm:j_idt42:0:j_idt73:0:j_idt102".
核心疑问:是否存在可行方案,能够从第二层嵌套的<ui:repeat/>内部,更新外层的重复渲染组件?
问题根源是JSF/PrimeFaces的命名容器(NamingContainer)查找规则:<ui:repeat>本身是独立的命名容器,在第二层嵌套的<ui:repeat>内部写相对ID(比如group、users)时,搜索范围只会限定在当前内层迭代容器的命名空间内,自然找不到外层的父级/兄弟组件。
可行实现方案如下:
- 使用相对路径向上查找:在组件搜索表达式中用
../向上跳出一层命名容器。以上述第二版代码为例,只需要把按钮的update属性从update="users"改成update="../users"即可——../会跳出当前内层<ui:repeat>的命名空间,直接在<p:card>的作用域下查找id为users的面板组,就能精准定位到当前分组对应的用户列表容器。如果需要更新整个<p:card>组件,将属性写成update="../"即可,跳出内层迭代容器后直接选中父级card组件。 - 绝对路径写法可作为备选:从ID固定的
<h:form>容器开始写完整组件路径,但由于<ui:repeat>会自动为每一行生成的组件拼接行索引前缀,绝对路径需要动态匹配行索引,实现复杂度远高于相对路径写法,日常开发不推荐使用。 - 额外提示:代码中存在标签拼写错误,
<p:outptuText>的正确写法为<p:outputText>,该错误不影响本次组件查找逻辑,但会导致文本渲染异常,建议一并修正。
内容的提问来源于stack exchange,提问作者Jan Dvořák

