Two different SelectItems return one selected value

I have a country class:

public class Country{
     private Long id;
     private String name;
}

      

and a class of a person who has two country fields

public class Person{
    private Country nationality;
    private Country nationality2;
}

      

Now in JSF I am using <f:selectItems>

to return a list of countries to select nationalities like this:

<h:form id="form1">
    <h:selectOneMenu value="#{mybean.person.nationality.id}">
         <f:selectItems value="#{mybean.countryList}" var="var" itemValue="#{var.id}"/>
    </h:selectOneMenu>

    <h:selectOneMenu value="#{mybean.person.nationality2.id}">
         <f:selectItems value="#{mybean.countryList}" var="var" itemValue="#{var.id}"/>
    </h:selectOneMenu>
    <p:commandButton actionListener="#{mybean.save}" update="sometable @form"/>
</h:form>

      

Now the weird problem is that when the form is submitted, the value assigned to the second field (nationality2) is assigned to both nationality and nationality2 regardless of what was selected for the first field. For example, if selected value for nationality is 1

and selected value for nationality2 is 2

when I submit the form both fields have the value 2

. Why is this happening?

PS: JSF implementation - Mojarra 2.1.3

+3


source to share


2 answers


Your specific problem is caused by you setting copies of the same reference Country

as the selected value and then only manipulating the property id

. All changes made in one link are reflected in all other links.

eg.

Country country = new Country();
person.setNationality1(country);
person.setNationality2(country);
country.setId(1); // Gets reflected in both nationalities!

      

Better to set an integer entity Country

as a value rather than manipulate its properties. Create Converter

one that converts between Country

and id

:



@FacesConverter(forClass=Country.class)
public class CountryConverter implements Converter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return (value instanceof Country) ? ((Country) value).getId() : null;
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (value == null || value.isEmpty()) {
            return null;
        }

        if (!value.matches("\\d+")) {
            throw new ConverterException(new FacesMessage("Invalid country ID: " + value));
        }

        Long countryId = Long.valueOf(value);
        MyBean myBean = context.getApplication().evaluateExpressionGet(context, "#{myBean}", MyBean.class);

        for (Country country : myBean.getCountries()) {
            if (countryId.equals(country.getId())) {
                return country;
            }
        }

        throw new ConverterException(new FacesMessage("Unknown country ID: " + value));
    }

}

      

and use it like this:

<h:selectOneMenu value="#{mybean.person.nationality1}">
     <f:selectItems value="#{mybean.countries}" var="country" itemValue="#{country}" itemLabel="#{country.name}" />
</h:selectOneMenu>
<h:selectOneMenu value="#{mybean.person.nationality2}">
     <f:selectItems value="#{mybean.countries}" var="country" itemValue="#{country}" itemLabel="#{country.name}" />
</h:selectOneMenu>

      

+2


source


Try using a second selectOneMenu

different name for var

. For example:

<h:selectOneMenu value="#{mybean.person.nationality2.id}">
         <f:selectItems value="#{mybean.countryList}" var="var2" itemValue="#{var2.code}"/>
    </h:selectOneMenu>

      

Otherwise, you will overwrite your changes in the (first) variable var

by changing the second selectOneMenu

.



EDIT:
If that doesn't solve the problem, try running tests to create the second countryList

(countryList2) and attach it to the second selectOneMenu

.

If the value remains unchanged, the error must be in getters or setters.

+1


source







All Articles