I got
j_idt7:city: Validation Error: Value is not valid
Cutting to the cheese, ManagedBean code:
//few imports here
@ManagedBean
@SessionScoped
public class CountriesAndCities implements Serializable{
private List<SelectItem> countries;
private List<SelectItem> cities;
private Map<String,List> m;
private String selectedCountry;
public String getSelectedCountry() {
return selectedCountry;
}
public void setSelectedCountry(String selectedCountry) {
this.selectedCountry = selectedCountry;
}
public CountriesAndCities(){
countries = new ArrayList<SelectItem>();
cities = new ArrayList<SelectItem>();
m = new HashMap<String,List>();
m.put("France", Arrays.asList("paris","marseille"));
m.put("England", Arrays.asList("Munchester","liverpoor"));
}
public List<SelectItem> getCountries(){
cities.removeAll(cities);
countries.removeAll(countries);
countries.add(new SelectItem("select country"));
for(Map.Entry<String, List> entry: m.entrySet()){
countries.add(new SelectItem(entry.getKey()));
}
return countries;
}
public List<SelectItem> getCities(){
for(Map.Entry<String, List> entry: m.entrySet())
{if(entry.getKey().toString().equals(selectedCountry)){
cities.addAll(entry.getValue());
break;
}
}
return cities;
}
public void checkSelectedCountry(ValueChangeEvent event){
selectedCountry = event.getNewValue().toString();
}
Here’s the snippet of my .xhtml :
<h:selectOneMenu immediate="true" value="#{countriesAndCities.selectedCountry}"
onchange="submit()" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
<f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
</h:selectOneMenu>
<br/>
<h:selectOneMenu id="city">
<f:selectItems value="#{countriesAndCities.cities}"></f:selectItems>
</h:selectOneMenu>
</h:form>
The code does what is supposed to be, But I get the error mentioned above at first line, only when i click on England and select country choices, I dunno why, I’ve written the same task in Ajaxized code, and It worked fine, any hand would be dead thankful .
The error
Validation Error: Value is not validwill be thrown when theequals()test of the selected item has not returnedtruefor any of the available items in the list. So, it has basically the following two causes:equals()method of the item value type is missing or broken.The item value type is
String, so itsequals()method is undoubtedly properly implemented (else it would break everything in Java world). So cause 1 can be scratched. Left over cause 2. Yes, indeed, you’re emptying the list of available cities in the getter of countries for some unclear reason.This code just doesn’t make sense. The getter is also called when the selected country is to be validated. This way the selected city can’t be found in the list of available cities when it’s about to be validated later on. By the way, your
getCities()also doesn’t make any sense. You’re looping over the whole map instead of just usingMap#get().This all is just broken code design. Getters should not contain any business logic at all. Getters should solely return bean properties. Those bean properties should already be preinitialized long before in (post)constructor or in action(listener) method.
How to fix this is a good second problem. The
<h:selectOneMenu valueChangeListener>is basically abused here. It’s the wrong tool for the job. You should be using<f:ajax listener>for this instead. But if you really insist in abusing thevalueChangeListenerfor the job, then you should have solved it as follows, whereby you queue theValueChangeEventtoINVOKE_APPLICATIONphase and perform the job during that phase (as if it were an (ajax) action listener method):Note that this still causes potential problems when you have some form validation around. A much better solution is to just use
<f:ajax>instead.See also:
selectOneMenuwiki page – at the bottom you can find a proper<f:ajax>example.