Sunday 31 March 2013

How to fix “form: xxxxxx: Validation Error: Value" is not valid problem – 2

“form: xxxxxx: Validation Error: Value"

BalusC comments: “the list behind <f:selectItems value /> does not contain the submitted value during processing of the form submit request as per the Object#equals() contract.”  He says this may be caused because of problems in the equals() method.

PrimeFaces online showcase example does not have this problem.  They probebly solved it in the coming versions.

For the time being I developed an other solution.  I changed the types od selects from hashMap to SelectItem lists as seen below:

asrSelect3.xhtml
-----------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h=http://java.sun.com/jsf/html
      xmlns:f=http://java.sun.com/jsf/core
      xmlns:p="http://primefaces.org/ui">

<h:head><title>PrimeFaces ARS Test</title>
</h:head>

<h:body>

<div align="center">

<h1 class="ui-widget-header ui-corner-all" align="center">PrimeFaces ARS Test</h1>

<br/>

<p:fieldset legend="Multiple Selects">

<h:form id="form">

    <p:messages id="msgs" showDetail="true" />
                          
       <p:panel header="Double Combo" style="margin-bottom:10px;">
        <h:panelGrid columns="2" cellpadding="5">
          Continent:
               <h:selectOneMenu id="continent" value="#{arsBean3.continent}">
                 <f:selectItems value="#{arsBean3.continents}"/>
                 <f:ajax render="countries" listener="#{arsBean3.handleContinentChange2}" />
               </h:selectOneMenu>

                    <br/>Country:
                      <h:selectOneMenu value="#{arsBean3.country}"
                                       id="countries">
                        <f:selectItems value="#{arsBean3.countries}"/>
                      </h:selectOneMenu>
        </h:panelGrid>

        <p:separator />
           
             <p:commandButton value="Submit" update="msgs" actionListener="#{arsBean3.displayLocation}" id="btnSubmit"/>

       </p:panel>
 
</h:form>

</p:fieldset>

<br/>

</div>

</h:body></html>

arsBean3.java
-------------------
package ars.primefaces.ajax;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.SelectItem;
import javax.faces.bean.ManagedBean;

import javax.faces.bean.SessionScoped;
 
@ManagedBean
@SessionScoped
public class ArsBean3 implements Serializable {

                private String continent;
                private String country;
              
                private List<SelectItem> continents = new ArrayList<SelectItem>(); 

                private Map<String,List<SelectItem>> countryDetailsData = new HashMap<String, List<SelectItem>>();
              
                private List<SelectItem> countries = new ArrayList<SelectItem>();

                public ArsBean3() {
         
                               continents.add(new SelectItem("Europe"));
                               continents.add(new SelectItem("Asia"));
                               continents.add(new SelectItem("America"));                           

                               List<SelectItem> countryDetailsEurope = new ArrayList<SelectItem>();

                               countryDetailsEurope.add(new SelectItem("Germany"));
                               countryDetailsEurope.add(new SelectItem("Britain")); 
                               countryDetailsEurope.add(new SelectItem("France"));
                             
                               List<SelectItem> countryDetailsAmerica = new ArrayList<SelectItem>();

                               countryDetailsAmerica.add(new SelectItem("US")); 
                               countryDetailsAmerica.add(new SelectItem("Canada")); 
                               countryDetailsAmerica.add(new SelectItem("Mexico"));
                           
                               List<SelectItem> countryDetailsAsia = new ArrayList<SelectItem>();

                               countryDetailsAsia.add(new SelectItem("Turkey"));
                               countryDetailsAsia.add(new SelectItem("Russia")); 
                               countryDetailsAsia.add(new SelectItem("China"));                              

                               countryDetailsData.put("Europe", countryDetailsEurope);
                               countryDetailsData.put("America", countryDetailsAmerica);
                               countryDetailsData.put("Asia", countryDetailsAsia);
                }
          
                public String getContinent() {
                               return continent;
                }

                public void setContinent(String continent) {
                               this.continent = continent;
                }

                public String getCountry() {
                               return country;
                }

                public void setCountry(String country) {
                               this.country = country;
                }

                public List<SelectItem> getContinents() {
                               return continents;
                }

                public void setContinents(List<SelectItem> continents) {
                               this.continents = continents;
                }
           
                public Map<String, List<SelectItem>> getCountryDetails() {
                               return countryDetailsData;
                }

                public void setCountryDetails(Map<String, List<SelectItem>> countryDetailsData) {
                               this.countryDetailsData = countryDetailsData;
                }
               
                public List<SelectItem> getCountries() {
                               return countries;
                }

                public void setCountries(List<SelectItem> countries) {
                               this.countries = countries;
                }
            
                public void handleContinentChange2(AjaxBehaviorEvent evt) {
                              
                               if(continent !=null && !continent.equals(""))
                                               countries = countryDetailsData.get(continent);
                               else
                                               countries = new ArrayList<SelectItem>();                         

                               country=countries.iterator().next().getLabel();

                               System.out.println(country);
                               System.out.println(countries);
                }
             
    public void displayLocation() {                             
        FacesMessage msg = new FacesMessage("Selected", "Continent:" + continent + ", Country: " + country);

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
}
 
It worked.  Then I carried the same variable types and used Primefacesmultiselect and ajax call.
This also worked correctly.
 

arsSelect4.xhtml
-----------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h=http://java.sun.com/jsf/html
      xmlns:f=http://java.sun.com/jsf/core
      xmlns:p="http://primefaces.org/ui">

<h:head><title>PrimeFaces ARS Test</title>

</h:head>

<h:body>

<div align="center">

<h1 class="ui-widget-header ui-corner-all" align="center">PrimeFaces ARS Test</h1>

<br/>

<p:fieldset legend="Multiple Selects">

<h:form id="form">

    <!-- p:growl id="msgs" showDetail="true"/-->
    <p:messages id="msgs" showDetail="true"/>                        

       <p:panel header="Double Combo" style="margin-bottom:10px;">
        <h:panelGrid columns="2" cellpadding="5">
            <p:selectOneMenu id="continent" value="#{arsBean4.continent}">
                <f:selectItem itemLabel="Select Continent" itemValue="" />
                <f:selectItems value="#{arsBean4.continents}" /&gt
                <p:ajax update="form:countries"
                        listener="#{arsBean4.handleContinentChange}" />
            </p:selectOneMenu>

            <p:selectOneMenu id="countries" value="#{arsBean4.country}">
                <f:selectItem itemLabel="Select Country" itemValue="" />
                <f:selectItems value="#{arsBean4.countries}" />
            </p:selectOneMenu>
        </h:panelGrid>
        <p:separator />
           
             <p:commandButton value="Submit" update="msgs" actionListener="#{arsBean4.displayLocation}" id="btnSubmit"/>

       </p:panel> 

</h:form> 

</p:fieldset>

<br/>

</div>

</h:body></html>

arsBean4.java
-------------------
package ars.primefaces.ajax;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.SelectItem;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class ArsBean4 implements Serializable {

                private String continent;
                private String country;
              
                private List<SelectItem> continents = new ArrayList<SelectItem>();

                private Map<String,List<SelectItem>> countryDetailsData = new HashMap<String, List<SelectItem>>();
              
                private List<SelectItem> countries = new ArrayList<SelectItem>();

                public ArsBean4() {
              
                               continents.add(new SelectItem("Europe"));
                               continents.add(new SelectItem("Asia"));
                               continents.add(new SelectItem("America"));                             

                               List<SelectItem> countryDetailsEurope = new ArrayList<SelectItem>();

                               countryDetailsEurope.add(new SelectItem("Germany"));
                               countryDetailsEurope.add(new SelectItem("Britain")); 
                               countryDetailsEurope.add(new SelectItem("France"));
                          
                               List<SelectItem> countryDetailsAmerica = new ArrayList<SelectItem>();

                               countryDetailsAmerica.add(new SelectItem("US")); 
                               countryDetailsAmerica.add(new SelectItem("Canada")); 
                               countryDetailsAmerica.add(new SelectItem("Mexico"));
                             
                               List<SelectItem> countryDetailsAsia = new ArrayList<SelectItem>();

                               countryDetailsAsia.add(new SelectItem("Turkey"));
                               countryDetailsAsia.add(new SelectItem("Russia")); 
                               countryDetailsAsia.add(new SelectItem("China")); 
                           
                               countryDetailsData.put("Europe", countryDetailsEurope);
                               countryDetailsData.put("America", countryDetailsAmerica);
                               countryDetailsData.put("Asia", countryDetailsAsia);
                }             

                public String getContinent() {
                               return continent;
                }

                public void setContinent(String continent) {
                               this.continent = continent;
                }
 
                public String getCountry() {
                               return country;
                }

                public void setCountry(String country) {
                               this.country = country;
                }

                public List<SelectItem> getContinents() {
                               return continents;
                }

                public void setContinents(List<SelectItem> continents) {
                               this.continents = continents;
                }          

                public Map<String, List<SelectItem>> getCountryDetails() {
                               return countryDetailsData;
                }

                public void setCountryDetails(Map<String, List<SelectItem>> countryDetailsData) {
                               this.countryDetailsData = countryDetailsData;
                }
              
                public List<SelectItem> getCountries() {
                               return countries;
                }

                public void setCountries(List<SelectItem> countries) {
                               this.countries = countries;
                }         

                public void handleContinentChange() {
                               
                               if(continent !=null && !continent.equals(""))
                                               countries = countryDetailsData.get(continent);
                               else
                                               countries = new ArrayList<SelectItem>();                          

                               country=countries.iterator().next().getLabel();

                               System.out.println(country);
                               System.out.println(countries);
                }              

    public void displayLocation() {                             
        FacesMessage msg = new FacesMessage("Selected", "Continent:" + continent + ", Country: " + country);

        FacesContext.getCurrentInstance().addMessage(null, msg);
    }
}

                                                                         

My solution to a temporary problem in the primefaces showcase multiselect and AJAX usage is to change the variable types used for the selectitems.  It certainly solves the problem as seen above.

Kind regards.

 Ali R+ SARAL