Reputation: 5858
Let's say I am using rendered
as basically a case statement. I have a label and message for an input field, but I want the field itself to change depending on the case. As such:
<p:inputText id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsInput}" />
<p:calendar id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsCalendar}" />
If I do that then I get the following error: java.lang.IllegalStateException: Component ID j_idt64:foo has already been found in the view.
As a workaround I created lots of labels/messages for each param type and changed their ids. But this brings my question. If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file? Is there a way to keep them with all the same ID?
Upvotes: 3
Views: 5895
Reputation: 14363
If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file?
How would JSF know that only one component will be rendered? You are using EL
in rendered
and both can evaluate to true. Here is the documentation which says you can't have duplicate ids inside a naming container.
The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer.
-
Is there a way to keep them with all the same ID?
In case you still want to have same ids on more than one components you need to separate the naming container.
You can use PanelGrid as a naming container.
Upvotes: 4
Reputation: 1108632
JSF component IDs are supposed to be unique during view build time already, not during view render time only. This way you effectively end up with two JSF components with the same ID which is indeed invalid. You'd like to effectively end up with one JSF component with the desired ID in the JSF component tree after view build time.
You can achieve this by populating the component during the view build time instead of generating its HTML output conditionally during the view render time. You can use the JSTL <c:if>
tag for this.
<c:if test="#{paramIsInput}">
<p:inputText id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
<c:if test="#{paramIsCalendar}">
<p:calendar id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
This has however caveats: the <c:if test>
condition can't depend on a variable which is only known during JSF render time. So it has not to depend on var
of a JSF iterating component, or to be a property of a view scoped bean, etc.
Upvotes: 10