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

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" />

Related

p:input will not render value attribute

I have a problem rendering p:inputText from primefaces.
Their Demo at http://www.primefaces.org/showcase/ui/input/inplace.xhtml is working. If I change it to my requirements it fail.
In my .xhtml I've the following code. The first part will print out the given ipaddress as plain text,
#{hostEntryManaged.selectedEntry.ipAddress}
but the value attribute of the p:inputText keeps blank. Nothing to see in the final html.
<h:outputLabel for="ipaddr" value="IP: " />
<p:inplace id="ipaddr" editor="true" >
<p:inputText value="#{hostEntryManaged.selectedEntry.ipAddress}" required="true" label="text" />
</p:inplace>
I can add
value="#{hostEntryManaged.selectedEntry.ipAddress}" also to the p:inplace. There it works fine, till I click the field and it turns to the (desired) input field.
It feels that the <p:inputText..../> is out of scope, so it can't access my bean.
But there are no errors.

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

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

Javascript error in XHTML page in JSF 2

I have the following code in an xhtml page in JSF 2. But when the page loads I get an javascript error that
document.getElementById("country") is null or not an object.
Why is this happening?
<h:form>
<h:panelGrid columns="2">
Selected country locale :
<h:inputText id="country" value="#{country.localeCode}" size="20" />
Select a country {method binding}:
<h:selectOneMenu value="#{country.localeCode}" onchange="submit()"
valueChangeListener="#{country.countryLocaleCodeChanged}">
<f:selectItems value="#{country.countryInMap}" />
</h:selectOneMenu>
<script>
alert("hi");
document.getElementById("country").disabled=true;
</script>
</h:panelGrid>
</h:form>
It's not finding your component. Since your <h:inputText> is inside of an <h:form> the id will have the following pattern
formName:componentName. Since you did not specify an id for <h:form>, JSF will generate one for you. That's why you are seeing j_id1926454887_72d35e53:country where j_id1926454887_72d35e53 is the form id. If you want to deal with simpler id, then you should add an id value to your <h:form>. For example
<h:form id="form">
<h:inputText id="country" value="#{country.localeCode}" size="20" />
</h:form>
The id for <h:inputText> will now be form:country.
Even simpler, you could simply add prependId = "false" to your form
<h:form prependId="false">
and now your id for <h:inputText> will simply be country.
How can I get this id dynamically?
I'm going to modify your code slightly to achieve what you want (I'm thinking that you want to disable the input based on a specific event). Consider this simpler example
<h:form>
<h:inputText id="country" value="#{country.localeCode}" size="20" onclick="disableInputText(this.form)" />
</h:form>
Here I'm attaching a javascript function to an HTML DOM Event handler. In this case, I want the input to be disabled when I click on it (hence onclick). I'm also passing the form as a reference in the function. Then, define your Javascript like this.
<script>
function disableInputText(form) {
form[form.id + ":country"].disabled = true;
}
</script>
We simply grab the input in the javascript with the corresponding id via the object form and set its disabled attribute to true. (You can sort of view the form object as Map).
Also check the link below for more attributes of <h:inputText> and the different handlers you can use (the ones with on as prefix).
inputText Tag Attribute.
Also, check out the answer with the most votes to get a bigger picture on how ids are generated and other ways on how they can be determined.
How can I know the id of a JSF component so I can use in Javascript
It's seems to be a naming issue. the id of the field is not rendered as country.
i found a question that seems relevant. Composite components & ID

JSF 1.2/Seam 2.2 - validator is skipped when input it empty

I am trying to call validateLength in JSF (xhtml file of seam)
<f:validateLength minimum="2" maximum="512"/>
It works for values such as text length 513 and 1 (i.e. it shows a warning, but not for 0)
The input text filed for which it is being used is set to required=false (so that it can use a4j support for empty fields, I have to show a preview based on the input)
The problem that I see is that there a validator method in a helper class but it gets ignored when the length of input is 0 (ie I put nothing , it works for non-empty values).
I also have a NullableStringConverter here but what I have noticed that as soon as that converter sets the value of null of empty string, the validator gets skipped. Here is the complete snippet of in the inputText
<h:inputText id="linkNameInput"
value="#{someHelper.name}"
validator="#{someHelper.validateMethod}"
required="false">
<f:validateLength minimum="2" maximum="512"/>
<f:converter converterId="NullableStringConverter" />
</h:inputText>
I would just like the ability to validate an empty string in a validator.
I would just like the ability to validate an empty string in a validator.
That's not possible in JSF 1.x. That's only possible since JSF 2.0 (in favour of JSR303 Bean Validation support).
I'm not sure why you'd like to validate the empty string in the custom validator. There you normally use the required="true" attribute for this. If the sole goal is to change the required message, then just use requiredMessage attribute.
<h:inputText ... required="true" requiredMessage="Please enter name" />
As mentioned already, validating an empty input String in a JSF 1.2 component is not supported. However, you can check for this null/empty model value in your backing bean on form submit and add a FacesMessage that is mapped to that specific input field. This would allow integration with server-side component-specific error message display (<h:message for="componentId" />).
FacesContext.getCurrentInstance().addMessage("componentId",
facesMessageForComponent);

Seam validation question - check for at least one field filled

I have a situation in my form that the user must fill at least one of the fields. Using "required" command, i cannot do that. What is the best way to validate this in seam ? i dont want to use javascript.
Thanks!
Just let the required attribute depend its outcome on the presence of the other input fields in the request parameter map.
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" required="#{empty param['form:input2'] and empty param['form:input3']}" />
<h:inputText id="input2" value="#{bean.input2}" required="#{empty param['form:input1'] and empty param['form:input3']}" />
<h:inputText id="input3" value="#{bean.input3}" required="#{empty param['form:input1'] and empty param['form:input2']}" />
</h:form>
Alternatively you could also make use of component binding and use UIInput#getValue() to check the value of the previous components and UIInput#getSubmittedValue() to check them for the yet-to-be-validated components (components are processed in the order as they appear in the component tree). This way you don't need to hardcode client ID's. You only need to ensure that binding names doesn't conflict with existing managed bean names.
<h:form>
<h:inputText binding="#{input1}" required="#{empty input2.submittedValue and empty input3.submittedValue}" />
<h:inputText binding="#{input2}" required="#{empty input1.value and empty input3.submittedValue}" />
<h:inputText binding="#{input3}" required="#{empty input1.value and empty input2.value}" />
</h:form>
JSF2 will let you do a form-level validation. For now, you'll have to make do with either:
Validate in a Bean after form
submission and populate a
FacesMessage to the user if it fails.
Add a validator to one field and in
that validator load in the other
fields and check their values.
If you dont want to use required attribute or javascript, then there are two ways.
One of them is creating a validator, but in my opinion that is too overkill.
I would just check if the input is null or empty in your bean.
if ("".equals(theFieldYouWantToCheck) || theFieldYouWantToCheck == null) {
//Either throw exception or return "false" so that you can handle it
}
If you are using RichFaces then you could perform the validation as follows (see http://mkblog.exadel.com/ria/richfaces-ria/richfaces-built-in-client-functions/):
<h:form id="form">
<h:inputText id="input1" value="#{bean.input1}" />
<h:inputText id="input2" value="#{bean.input2}"
required="#{empty rich:findComponent('input1').submittedValue}"
requiredMessage="At least one of the fields input1 and input2 must be filled."/>
</h:form>
Note that the expression rich:findComponent('input1') is equivalent to uiComponent['input1']. The reason is that Seam provides the dynamic map uiComponent to look up UI components.

Resources