在JSF中,<ui:repeat/>
和类似组件(如PrimeFaces <p:dataTable/>
根据迭代索引为子组件生成动态ID,即:
<p:dataTable id="table" var="item" value="#{itemList}">
<h:outputText id="name" value="#{item.name}"/>
</p:dataTable>
将生成如下内容:
<table id="table">
<span id="table:0:name">name0</span>
<span id="table:1:name">name1</span>
<span id="table:2:name">name2</span>
...
<span id="table:n:name">nameN</span>
</table>
因此所有元素都明确具有不同的客户端ID。我故意跳过<tr/>
,<td/>
等
因此,<p:ajax ... update=":table:name"/>
引用表中的所有名称并且工作正常,<p:ajax ... update=":table:#{someDesiredIndex}:name"/>
失败并显示类似于SEVERE: javax.faces.FacesException: Cannot find component with identifier ":table:0:name" in view.
事件的消息,但我可以确认该组件存在于标记。是不是可以这样做?
我正在运行GlassFish 3.1.2和Mojarra 2.1.6,以防它相关。
答案 0 :(得分:12)
它确实不存在于UIViewRoot#findComponent()
可遍历的JSF组件树中。它仅存在于生成的HTML输出中。 JSF组件树中只有一个<h:outputText id="name">
,而不是你想象的那么多。在生成HTML输出时,它被重复使用了多次。最好的情况是,您可以通过table:name
获取物理组件,但这反过来又不存在于HTML DOM树中,因此在执行ajax更新期间document.getElementById()
将失败。
为了实现具体的功能需求,您基本上需要一个物理现有组件来表示JSF组件树中的行。如果使用视图构建时标记(例如JSTL <c:forEach>
)而不是视图渲染时间标记,则可以在循环中创建它们。
<table id="table">
<c:forEach items="#{itemList}" var="item" varStatus="loop">
<tr><td><h:outputText id="table_#{loop.index}_name" value="#{item.name}" /></td></tr>
</c:forEach>
</table>
这将在JSF组件树中物理创建多个组件,并将其呈现为:
<table id="table">
<span id="table_0_name">name0</span>
<span id="table_1_name">name1</span>
<span id="table_2_name">name2</span>
...
<span id="table_n_name">nameN</span>
</table>
您可以通过以下方式引用它们: update=":table_#{someDesiredIndex}_name"
。
更新:由于Mojarra 2.2.5,<f:ajax>
不再验证客户端ID,渲染器能够遍历迭代组件以找到正确的迭代轮次渲染。因此,以这种方式引用<f:ajax>
中的迭代索引应该可以正常工作。它只在当前的MyFaces 2.2.7 / PrimeFaces 5.1版本中不起作用,但预计它们将在未来版本中赶上它。