2

I have 2 <h:selectOneMenu> components and one of them depends of the selection of the other. When you select one value of the first menu component, then the second changes with the event of onchange="submit()" and valueChangeListener="#{Usuario.cmbDatos_action}" of the first menu:

<h:selectOneMenu id="cmbCombo" binding="#{Usuario.cmbDatos}" value="#{Usuario.id}" 
    onchange="submit()" valueChangeListener="#{Usuario.cmbDatos_action}">
    <f:selectItems value="#{beanCombos.datos}"></f:selectItems>
</h:selectOneMenu>

It is like Countries and Cities of the selected Country. The first menu is loaded as follows:

@ManagedBean
@RequestScoped
public class BeanCombos {

    private List<SelectItem> Datos;

    public BeanCombos() {
        try {
            clsConexion objConexion = new clsConexion();
            String strSQL = "SELECT * FROM Usuarios";            
            objConexion.ResultSetSQL = objConexion.EjecutarConsulta(strSQL);
            Datos = new ArrayList<SelectItem>();

            while (objConexion.ResultSetSQL.next()) {
                Usuario objUsuario = new Usuario();                
                objUsuario.setId(String.valueOf(objConexion.ResultSetSQL.getInt("Codigo")));
                objUsuario.setNombre(objConexion.ResultSetSQL.getString("Nombres").toUpperCase());
                Datos.add(new SelectItem(objUsuario.getId(), objUsuario.getNombre()));
            }
        } catch(Exception ex) {
            String strError = ex.getMessage().toString();            
        }
    }

    public List<SelectItem> getDatos() {
        return Datos;
    }
}

But when I select one value of the first menu I don't know how load the next menu. I've tried it as follows:

public String cmbDatos_action() {
    try {
        int intValor = Integer.parseInt(cmbDatos.getValue().toString());
    } catch(Exception ex) {

    }

    return null;
}

In what part of method cmbDatos_action() can I put the code to load the second menu?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555

1 Answers1

10

The valueChangeListener should refer a method taking ValueChangeEvent argument and returning void.

public void cmbDatos_action(ValueChangeEvent event) {
    // ...
}

But you will run into trouble with regard to validation because you're basically submitting the entire form with onchange="submit()". You'd need to add immediate="true" to the first menu component as well. See also this article for a detailed explanation with concrete examples.

As you seem to be already using JSF 2.x, I recommend to forget this JSF 1.x based workaround and just go straight with the JSF 2.x <f:ajax> approach which is so much simpler to program.

Here's a kickoff example, based on "Countries" and "Cities" example:

<h:selectOneMenu value="#{bean.country}" converter="countryConverter">
    <f:selectItems value="#{bean.countries}" var="country" itemValue="#{country}" itemLabel="#{country.name}" />
    <f:ajax listener="#{bean.changeCountry}" render="cities" />
</h:selectOneMenu>
<h:selectOneMenu id="cities" value="#{bean.city}" converter="cityConverter">
    <f:selectItems value="#{bean.cities}" var="city" itemValue="#{city}" itemLabel="#{city.name}" />
</h:selectOneMenu>

with for example

@ManagedBean
@ViewScoped
public class Bean {

    private List<Country> countries;
    private Country country;
    private List<City> cities;
    private City city;

    @EJB
    private DataService service;

    @PostConstruct
    public void init() {
        countries = service.getCountries();
    }

    public void changeCountry() {
        cities = service.getCities(country);
    }

    // ...
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555