Daniel Moses
Daniel Moses

Reputation: 5858

JSF same ID on rendered

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

Answers (2)

Bharat Sinha
Bharat Sinha

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

BalusC
BalusC

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.

See also:

Upvotes: 10

Related Questions