11

在 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 上运行以防万一。

4

1 回答 1

17

它确实不存在于 JSF 组件树中,因为UIViewRoot#findComponent(). 它仅存在于生成的 HTML 输出中。JSF 组件树中只有一个<h:outputText id="name">,而不是您所期望的多个。它只是在生成 HTML 输出时被多次重用。充其量,您可以通过 获取物理组件table:name,但这反过来又不存在于 HTML DOM 树中,因此document.getElementById()在执行 ajax 更新期间会失败。

无论如何,为了实现具体的功能需求,您基本上需要有一个物理存在的组件来表示 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 版本中还不起作用,但预计它们会在未来的版本中赶上它。

于 2013-04-16T17:58:06.083 回答