JSF form dynamic layout causes java.lang.IllegalStateException: component with duplicate id "j_id142" found - jsf

I am trying to build a dynamic layout for a form in JSF. It should generate a dynamic number of select fields, based on the values that come from "classifyingOptions", which is of type: Map(Object, List(Object)).
I first tried to use ui:repeat to iterate through the map, but I couldn't since the EL for the u:select and f:selectItems are evaluated when the view is built and is invalid since it relies on a variable only made available by the ui:repeat during rendering.(source for the explanation here
So i switched to using c:forEach.
<c:forEach items="#{action.classifyingOptions}" var="current" varStatus="i">
<h:panelGrid columns="2">
<u:select label="#{current.key.value}" id="select_#{i.index}" value="#{action.selectedOption}"
readonly="#{i.index != 0 ? !action.isSelected.get(i.index -1) : false }"
valueChangeListener="#{action.classifyingOptionChanged}" immediate="true">
<f:selectItems value="#{current.value}" var="option" itemValue="#{option.key}" itemLabel="#{option.value}" />
<a4j:ajax event="change" render="#form" execute="#this" />
</u:select>
<h:panelGroup />
</h:panelGrid>
</c:forEach>
I can read the map and show the select fields. The requirements is that when the first of the fields is selected, the next field needs to be enabled using an ajax call.
The problem is that an error is thrown on the sever once I select an option for the first field:
16.05.16 16:46:25:267 EEST] 0000006f FaceletViewDe E Error Rendering View[/pages/details.xhtml] java.lang.IllegalStateException: component with duplicate id "j_id142" found
In the browser, i get this message as part of the response that threw the error: This page contains the following errors: error on line 23 at column 230: Extra content at the end of the document
Below is a rendering of the page up to the first error.
So I used both ui:repeat and c:forEach, but none of them was able to work properly. Can you check where my mistake is? Or do you know any different approach?
Thank you!

Issue Solved. I used f:ajax instead of a4j:ajax

Related

What different between p:param and custom attribute

I suspect about 2 way of passing value through attribute.
First: f:param
<p:inputText value="#{inputTextView.inputVal}">
<f:param name="fieldA" value="inputA" />
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
Second: custom field
<p:inputText value="#{inputTextView.inputVal}"
fieldB="inputB">
<p:ajax process="#form" update="#form"></p:ajax>
</p:inputText>
The first way, I can get value of attribute by using
FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("fieldA");
While the second way use
UIComponent.getCurrentComponent(FacesContext.getCurrentInstance()).getAttributes().get("fieldB");
Does anyone know what different between first and second?
What situation which appropriate for use the first approach?
First of all, if you want to set a custom attribute, you cannot just add a random new attribute to a tag because JSF ignores unsupported tag attributes. BalusC gives some options on how to work around this in this answer.
f:param should be used if you want to add values to the query string or request parameters. It should be used with command components (e.g. h:commandButton, h:commandLink or h:outputLink).
f:attribute on the other hand, adds entries to the attribute Map of a component.

JSF 2 ui:repeat h:form h:inputText

Iam iterate a list of objects with ui:repeat.
For each Object h:form, h:inputText (for order value) and the commandLink for adding the Item will be generated.
<ui:repeat var="article" value="#{someDataBean.myArrayList}">
<h:form>
Value: <h:inputText value="#{baskedBean.articleValue"} />
<h:commandLink value="add" action="#{baskedBean.addArticel(article)}" />
</h:form>
</ui:repeat>
Lets suppose we have only one article, the order value (baskedBean.articleValue) is submitted and setted correctly.
If we have more than one article in the ui:repeat value list, the submitted value isnt setted. Expect i use the last article.
It looks like, that the other h:inputText components (under the current) will overwrite the value (baskedBean.articleValue)
I tought, that i could handle the problem by sourrunding the related article h:input and commandLink components by a dedicated h:form (only for the article) but it didn't work.
Iam using mojarra 2.2.4 (and testet it also with 2.2.3)
thanks
thanks for your help

JSF Ajax rerender <h:textInput ...> on Change

I am trying to get an h:textInput to rerender on change, I have tried it with a4j:ajax and f:ajax.
When using a4j:ajax:
<h:panelGroup id="xyzPG">
<ui:repeat var="var" ... >
...
<h:inputText id="#{idController.getIdXYZ(var.id)}"
value="#{someModel.value}"
size="3"
styleClass="#{errorController.getErrorStateStyleId(idController.getIdXYZ())}">
<a4j:ajax event="change" render="xyzPG" listener="#{listener.doSomeStuff}" />
</h:inputText>
...
</ui:repeat>
</h:panelGroup>
This works the first time, after the panel has updated the first time it stops updating the modell and the listener isn't called either. However the render is triggered causing the old values to be displayed.
Now when I replace a4j:ajax with f:ajax I get the error message that the id xyzPG cannot be found within xyzInput.
<f:ajax event="change" render="#this" listener="#{listener.doSomeStuff}" />
When I try limiting the rerender to the inputText it always updates the model and the listener is called, however the h:inputText is not rerendered.
I have already tried placing another panelGroup around the inputText but that didn't work either.
The reason why we are not using h:dataTable is because we have to produce a Table with the following layout:
----------------------------
| dataSet1 | dataSet 2 |
----------------------------
| dataSet3 | dataSet 4 |
etc...
Hence we are using the offset and step attributes of ui:repeat.
By design, you can't dynamically generate id attributes using a render-time tag like <ui:repeat/>
Compile-time V Render-time tags
For the purposes of view construction and ajax-updates, the ids of components must be available during view construction before a view is rendered. <ui:repeat/> already caters for uniqueness in the ids of it's child components. But if you require control of the ids, you need to use a compile-time tag handler like <c:forEach/>:
<c:forEach items="#{idController.itemsList}" var="theVar">
<h:inputText id="#{idController.getIdXYZ(theVar.id)}" value="#{someModel.value}" size="3" styleClass="#{errorController.getErrorStateStyleId(idController.getIdXYZ())}">
<a4j:ajax event="change" render="xyzPG" listener="#{listener.doSomeStuff}" />
</h:inputText>
<c:forEach/>
It's unlikely that you'll be able to reach xyzPG from within the <ui:repeat/> because the <ui:repeat/> is also a naming container, just like <h:panelGrid/> and so forth. The ajax update works with Richfaces because they've made special provisions for such use cases. <f:ajax/> however will not tolerate it. xyzPG is outside the scope of the <ui:repeat/> so to reach that component, you need to use a qualified naming convention:
<f:ajax event="change" render=":form1:xyzPG" listener="#{listener.doSomeStuff}"/>
This assumes that xyzPG is directly contained within an <h:form id="form1"/>
without seeing your backing bean code , I think you should use
<h:inputText id="#{idController.idXYZ}"
instead of
<h:inputText id="#{idController.getIdXYZ()}"

Cannot find component with identifier in View JSF

I was trying to show messages using a p:growl like this.to be updated on the OnRowSelect Method of a Data Table lazy loading like this
<p:growl id="applyMessages" showDetail="false" global="true" /> and <p:ajax event="rowSelect" listener="#{editBean.onRowSelect}" update=":studyPlanEditForm:display applyMessages"/>
but got the error like this
Cannot find component with identifier "applyMessages" in view.
Please Help.
Check the source code of your page in browser. Then identify the p:growl markup and its generated client-id. It surely is longer than applyMessages and has a prefix similar to containerID:applyMessages. Use this id in your update attribute of the ajax call.

<h:message> unable to find component in <ui:repeat>

I am building a table using a <ui:repeat> tag, and its length is dynamic. Each row has a <h:inputText> field. When the form is submitted, it sets the values from the form into a hashmap. That all works great, except for the validation. I need to tell the <h:message> which input it belongs to using the "for" attribute. I've tried to create a unique ID per row, based on the name of the item being used to create the row. But the <h:message> tag remains empty when I submit an invalid input, and I get the following output on the servers log (JBoss 7.1):
[javax.enterprise.resource.webcontainer.jsf.renderkit]
Unable to find component with ID nTAS in view.
Here is the XHTML:
<ui:repeat var="item" ...>
...
<h:inputText value="#{bean.chosenItems[item.name]}" id="n#{item.name}" >
<f:validateLongRange minimum="0" maximum="10" />
</h:inputText>
<h:message for="n#{item.name}" />
...
</ui:repeat>
In order to at least get some kind of error message in the browser, I also added this near the top of my page, and it works:
<h:messages styleClass="error" />
It displays this message:
j_idt13:j_idt17:1:n: Validation Error: Value is not of the correct type.
And that kind of shows part of the problem, since the ID is that strange code at the start of the message, and it starts with "n", but doesn't contain the item's name. If I look at the source in the browser, the ID is actually: id="j_idt13:j_idt17:1:nTAS"
If I look at other components, outside of the table, they also have cryptic IDs, apparently generated by JSF.
And what is really weird is that when I input "asdf" a second time, and re-submit the form, it then calls the action method on the bean, instead of again failing during validation phase!! How can that be?!
Thanks for any hints,
John
You cannot create IDs dynamically with el expressions. And the "cryptic" IDs are indeed generated by jsf if you don't assign an ID to a component.
But you don't need to care for the uniqueness of your ids in ui:repeat. JSF does it for you (the "1" in the generated id string is the counter for your repeated component). Just give your input field a "fixed" id and reference it in your h:message:
<h:inputText value="#{bean.chosenItems[item.name]}" id="myID" >
<f:validateLongRange minimum="0" maximum="10" />
</h:inputText>
<h:message for="myID" />

Resources