我有以下结构(内容和属性省略):
<ui:repeat id="outerlist">
<my:compositeComponent id="myCC">
<h:panelgroup id="container">
Some content here (outputText, etc.)
<ui:repeat id="innerlist">
<h:commandButton>
<f:ajax render=":#{cc.clientId}:container" />
<!-- all closing tags accordingly -->
由于容器内的内容取决于内部列表按钮的操作,我需要更新它。当没有外ui:repeat
时,如上所示的方法有效。但是,如果存在component not found
错误,则会失败。
这似乎是因为cc.clientId
然后本身包含外部ui:repeat
的行索引,例如outerlist:0:myCC:container
。如a comment to this answer所示,此索引ID在视图树的服务器端表示中不可用。而是“行索引仅存在于客户端”。我必须承认我不太明白这个索引是如何完成的以及服务器端的可用内容。
所以我的问题是:JSF如何进行这种索引,它是如何(在服务器上)将ui:repeat
内的不同“实例”分开的,并且有一个解决方案,我正在努力实现上述目标码?
答案 0 :(得分:3)
<f:ajax>
中指定的客户端ID必须在服务器端的两者中由JSF提供
facesContext.getViewRoot().findComponent(clientId);
(因此可以找到它以呈现ajax响应的新HTML表示形式)
客户端的和由JavaScript
组成document.getElementById(clientId);
(一旦新的HTML内容的ajax响应到达,它就可以被JS更新/替换)
由于<ui:repeat>
仅在视图呈现时间内运行,因此具有行索引的客户端ID不代表服务器端的有效组件(findComponent()
中的“无法找到组件...”错误) ,但它确实代表了客户端的有效HTML元素。基本上,您需要客户端ID,而不需要服务器端的行索引和客户端的行索引。但是这对<ui:repeat>
不起作用,因为它(不幸的是)不可能单独选择特定迭代的组件树状态findComponent()
。
在使用JSTL <c:forEach>
并在视图构建期间运行时动态分配组件ID并且实际上在视图树中生成多个完整的JSF组件而不是仅多次重复使用的组件时,它应该可以正常工作在渲染过程中。
<c:forEach varStatus="loop">
<my:compositeComponent id="myCC">
<h:panelGroup id="container_#{loop.index}">
Some content here (outputText, etc.)
<ui:repeat id="innerlist_#{loop.index}">
<h:commandButton>
<f:ajax render=":#{cc.clientId}:container_#{loop.index}" />
然而,这有其自身的含义,当然与复合组件一起使用时,以及在嵌套循环中使用时也是如此。您的代码不够完整,无法提供有关该代码的见解和建议。例如,当将这段代码放置在复合组件中时,它会断开,复合组件本身也在渲染时循环中重复使用多次。
答案 1 :(得分:0)
作为更新:在这种特殊情况下,使用c:foreach
不是一个选项,因为两个列表都需要是动态的(尽管这条路线在其他一些情况下给我省了很多麻烦)而是我添加了一个属性复合组件传递可选的“更新范围”,如下所示:
<cc:attribute name="updateScope" required="false" type="java.lang.String"
default=":#{cc.clientId}:container" />
通过设置默认值,我不需要在非循环上下文中更改组件的任何使用。但是,如果我想在ui:repeat
中使用它,我可以将ID传递给足够宽的属性以封闭外部循环。通常,这只是h:panelGroup id="wrapper"
附近的ui:repeat
。
显然,这有一些缺点:它会更新循环的所有子项,这可能会导致重新呈现大量不必要的内容。一个令人讨厌的副作用是重置这些兄弟姐妹的错误消息和本地值。在我们的一个页面中,它还使所有扩展的面板重置为关闭状态。
但是,如果这些问题不重要(例如:我的原始示例是指没有输入字段或面板但只有反馈文本和操作的组件),则附加属性可以是一种简单的工作方法围绕上述问题。
答案 2 :(得分:0)
我就这样解决了这个问题:
update=":#{cc.clientId.replaceAll(':[0-9]+:', ':')}"