Reputation: 1253
I have a jsf 1.2 app that has the following code:
<c:forEach items="#{test.customerList}" var="itm">
<h:panelGroup layout="block">
<h:panelGroup layout="block" style="float:left;">
<h:outputText value="#{itm.customerName}"/>
</h:panelGroup>
<h:panelGroup layout="block" style="float:right;">
<c:forEach items="#{itm.addressTypeList}" var="adrssType">
<h:graphicImage id="addressTypeIcon" url="/images/services/16x16#{adrssType.contactaddresstypeicon}" alt="#{adrssType.contactaddresstypedesc}" title="#{adrssType.contactaddresstypedesc}" style="margin-top:4px;margin-left:5px;" rendered="#{adrssType.contactaddresstypeid lt 6}"/>
</c:forEach>
</h:panelGroup>
</h:panelGroup>
</c:forEach>
I get a "javax.servlet.ServletException: duplicate Id for a component " exception on the second time I do a search for customers. I've narrowed the problem down to the line that starts with:
<h:graphicImage id="addressTypeIcon"
If I remove this line, I don't get the exception, but I also don't get the images I want to display. What would be causing this?
Upvotes: 3
Views: 1651
Reputation: 1108722
JSTL tags runs during view build time, that moment when the JSF component tree needs to be populated based on the JSP/XHTML file. Effectively, all JSF components which are nested inside <c:forEach>
are repeatedly recreated in the JSF component tree as many times as it needs to iterate. So when you use a hardcoded ID like as in the <h:graphicImage>
, then it'll end up duplicated in the component tree and hence cause this exception.
This "duplicate component ID" error wouldn't have occurred when you have used a JSF component to iterate over the collection instead of a JSTL taghandler, such as <h:dataTable>
, <ui:repeat>
, <t:dataList>
, <a4j:repeat>
, etc. There would then namely be only one <h:graphicImage>
in the JSF component tree which is then repeatedly reused to generate HTML output during the view render time, that moment when the HTML output needs to be produced based on the JSF component tree. Hereby JSF will automatically append the iteration index to the generated client ID so that the produced HTML DOM tree won't end up with duplicate HTML element IDs.
If you have no other option than the <c:forEach>
, then you should be appending the iteration index to the ID yourself. E.g.:
<c:forEach ... varStatus="loop">
<h:graphicImage id="addressTypeIcon_#{loop.index}" ... />
</c:forEach>
Alternatively, you could also remove the entire id
. JSF will then autogenerate one and hereby thus ensure uniqueness.
Upvotes: 4