José Castillo José Castillo - 1 year ago 73
Ajax Question

How to make three JSF h:selectOneMenus that depend on each other

I hope someone can help me. This is a "Category-Type-Item" situation where the user has to select from three different drop-down lists. In JSF I made it with three

. The first two
work OK. I read a solution here, about a "malformedXML" error when I tried the first time. That's the reason each selectOneMenu is surrounded by a
. I implemented it and work partially and only after reload (F5) the page, but this is not an acceptable solution.

Here is the code that I'm implementing:

<p:panel rendered="#{temporadaControllerExt.noHayGrupos}"
style="width: 650px">

<h:panelGrid columns="3">
<h:panelGroup id="fases">
<h:outputLabel value="Fase: "/>
<h:selectOneMenu value="#{temporadaControllerExt.faseSelectedFinal}">
<f:selectItems value="#{temporadaControllerExt.fases}"/>
<f:ajax render="grupos"/>

<h:panelGroup id="grupos">
<h:outputLabel value="Grupo: "/>
<h:selectOneMenu value="#{temporadaControllerExt.grupoSelected}"
<f:selectItems value="#{temporadaControllerExt.gruposDefase}"/>
<f:ajax render="jornadas"/>

<h:panelGroup id="jornadas">
<h:outputLabel value="Jornada: "/>
<h:selectOneMenu value="#{temporadaControllerExt.jornadaSelected}"
<f:selectItems value="#{temporadaControllerExt.jornadasEnGrupo}"/>

Of course is not complete, for space reasons. And here is part of the bean controller that I'm using:

@ManagedBean(name = "temporadaControllerExt")
public class TemporadaControllerExt extends TemporadaController {

private Fase fase;
private Grupo grupo;
private Jornada jornada;

private String faseSelectedFinal;
private String grupoSelected;
private String jornadaSelected;
private boolean grupoListDiseable = true;
private boolean jornadaListDiseable = true;

// a lot more declarations, and methods incluiding getters & setters not important for the answer...

//Entities Cache
private Map<String, Fase> mapFases = new HashMap<>();
private Map<String, Grupo> mapGrupos = new HashMap<>();

// use to enable the second selectOneMenu
public void setFaseSelectedFinal(String faseSelectedFinal) {
this.faseSelectedFinal = faseSelectedFinal;
this.grupoListDiseable = false;

public void setGrupoSelected(String grupoSelected) {
this.grupoSelected = grupoSelected;
this.jornadaListDiseable = false;

// methods used to populate the selecOneMenu's
public List<SelectItem> getFases(){
List<SelectItem> fasesList = new ArrayList<>();
fasesList.add(new SelectItem("-- Seleccione Fase --"));
for(Map.Entry<String, Fase> item : mapFases.entrySet()){
fasesList.add(new SelectItem(item.getKey()));
return fasesList;

public List<SelectItem> getGruposDefase(){
List<SelectItem> grupoList = new ArrayList<>();
grupoList.add(new SelectItem("-- Seleccione Grupo --"));

Fase faseSel = mapFases.get(faseSelectedFinal);
List<Grupo> grupoInt = faseSel.getGrupoList();
for(Grupo grp : grupoInt){
grupoList.add(new SelectItem(grp.getNombre()));

return grupoList;

public List<SelectItem> getJornadasEnGrupo(){
List<SelectItem> jornadaList = new ArrayList<>();
jornadaList.add(new SelectItem("-- Seleccione Jornada --"));

Grupo grupoSel = mapGrupos.get(grupoSelected);
for(Jornada jor : grupoSel.getJornadaList()){
jornadaList.add(new SelectItem(jor.getNumero().toString()));
return jornadaList;

As you can appreciate I'm using primefaces (3.4), and this panel is rendered in accordance to the value of the "noHayGrupos" boolean variable. This works OK, my problem is the selectOneMenu chain.

Answer Source

After some investigation on my problem, I found a solution. I read a tutorial in this place, the section relative to "Integrated Ajax Support in JSF 2.0" by Marty Hall. The solution was quite simple:

Declare a boolean variable to determinate if a comboBox is selected or not, and ask if a previous combobox has a data valid selected, and that's it, worked every thing. Here the code that I use in the method getGruposDefase():

public List<SelectItem> getGruposDefase() {
    List<SelectItem> grupoList = new ArrayList<>();
    grupoList.add(new SelectItem("-- Seleccione Grupo --"));

    if (!grupoListDiseable && (faseSelectedFinal != null)) {
        Fase faseSel = mapFases.get(faseSelectedFinal);
        List<Grupo> grupoInt = faseSel.getGrupoList();
        for (Grupo grp : grupoInt) {
            grupoList.add(new SelectItem(grp.getNombre()));
    return grupoList;

The variable grupoListDisable is used to control access to the second comboBox, and faseSelectedFinal, say if you have selected a valid item in the first comboBox. This simple solution makes the code work smoothly. Thanks Marty Hall