我有以下结构(省略内容和属性):
<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
时,上面所示的方法有效。但是,当存在组件时,它会失败并出现未找到组件
错误。
这似乎是由于 cc.clientId
本身包含外部 ui:repeat
的行索引,例如outerlist:0:myCC:container
。如a comment to this answer表示,此索引 ID 在 View 树的服务器端表示中不可用。相反,“行索引仅存在于客户端”。我必须承认我不太了解索引是如何完成的以及服务器端可用的内容。
所以我的问题是:JSF 如何进行此索引,它如何(在服务器上)在 ui:repeat
中分离不同的“实例”,以及是否有针对我正在尝试的解决方案用上面的代码来实现?
最佳答案
<f:ajax>
中指定的客户端 ID必须在 JSF 的服务器端两者中可用
facesContext.getViewRoot().findComponent(clientId);
(以便可以找到它,以便为 ajax 响应呈现新的 HTML 表示形式)
和在客户端由 JavaScript 实现
document.getElementById(clientId);
(这样一旦带有新 HTML 内容的 ajax 响应到达,它就可以被 JS 更新/替换)
作为<ui:repeat>
仅在 View 渲染时运行,具有行索引的客户端 ID 不代表服务器端的有效组件(来自 findComponent()
的“找不到组件...”错误),但它确实代表客户端中的有效 HTML 元素边。基本上,您需要服务器端不带行索引的客户端 ID 和客户端带行索引的客户端 ID。但这对 <ui:repeat>
不起作用因为(不幸的是)不可能单独选择特定迭代轮的组件树状态 findComponent()
.
使用 JSTL 时应该可以正常工作 <c:forEach>
并在 View 构建期间运行时动态分配组件 ID,并且实际上还在 View 树中生成多个完整的 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}" />
然而,这有其自身的含义,尤其是在与复合组件一起使用以及在嵌套循环中使用时。您的代码不够完整,无法提供有关此问题的见解和建议。例如,当这段代码被放置在一个复合组件中时,该组件本身也会在渲染时间循环中重复使用多次,它会中断。
另请参阅:
关于ajax - 如何寻址循环命名容器内的组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13457295/