In JSF, <ui:repeat/>
and similar components such as PrimeFaces <p:dataTable/>
generate dynamic ids for sub-components based on the iteration index, i.e.:
<p:dataTable id="table" var="item" value="#{itemList}">
<h:outputText id="name" value="#{item.name}"/>
</p:dataTable>
will generate something like this:
<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>
so all the elements clearly have a distinct client id. I intentionally skipped the <tr/>
, <td/>
, etc.
So, <p:ajax ... update=":table:name"/>
refers to all the names in the table and it works fine, <p:ajax ... update=":table:#{someDesiredIndex}:name"/>
fails with a message similar to SEVERE: javax.faces.FacesException: Cannot find component with identifier ":table:0:name" in view.
event though I can confirm that the component exists in the markup. Is it not possible to do this?
I'm running on GlassFish 3.1.2 and Mojarra 2.1.6 in case it is relevant.
It does indeed not exist in the JSF component tree as traversable by UIViewRoot#findComponent()
. It exists only in the generated HTML output. There's only one <h:outputText id="name">
in the JSF component tree, not multiple as you seemed to expect. It's just been reused multiple times when producing the HTML output. At best, you can get the physical component by table:name
, but this does in turn not exist in the HTML DOM tree, so the document.getElementById()
would fail on that during performing the ajax update.
In order to achieve the concrete functional requirement anyway, you basically need to have a physical existing component representing the row in the JSF component tree. You can create them in a loop if you use a view build time tag, such as JSTL <c:forEach>
, instead of a view render time tag.
<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>
This will create physically multiple components in the JSF component tree and this get rendered as:
<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>
And you can reference them via e.g. update=":table_#{someDesiredIndex}_name"
.
Update: since Mojarra 2.2.5, the <f:ajax>
doesn't validate the client ID anymore and the renderer is capable of walking through iterating components in order to find the right iteration round to render. So referencing the iteration index in <f:ajax>
this way should just work fine. It only doesn't work yet in current MyFaces 2.2.7 / PrimeFaces 5.1 versions, but it's expected that they will catch up it in a future version.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With