Ajax – Two ajax updates with h:selectOneMenu f:ajax

ajaxjsf

In short, if a component has been updated by Ajax, it can not launch new events Ajax

I have three h:selectOneMenu: A, B and C.
When I fire change event in A, then update the B h:selectOneMenu.
When I fire change event in B, then update the C h:selectOneMenu.

The problem is that when the content of B h:selectOneMenu is updated, the ajax in B don't work and C never can't be updated.

<h:selectOneMenu id="A" value="#{paqueteBean.mes}" label="a">
<f:selectItem itemLabel="Seleccione..." itemValue="" />
<f:selectItem itemLabel="Enero" itemValue="ENERO" />
<f:selectItem itemLabel="Febrero" itemValue="FEBRERO" />
<f:ajax listener="#{paqueteBean.changeMes}" render="B" />
</h:selectOneMenu>

<h:selectOneMenu id="B" value="#{paqueteBean.origen}" label="b">
<f:selectItem itemLabel="Seleccione..." itemValue="" />
<f:selectItems value="#{paqueteBean.origenes}" />
<f:ajax listener="#{paqueteBean.changeOrigen}" render="C"/>
</h:selectOneMenu>

<h:selectOneMenu id="C" value="#{paqueteBean.zona}" label="c">
<f:selectItem itemLabel="Seleccione..." itemValue="" />
<f:selectItems value="#{paqueteBean.zonas}" />
</h:selectOneMenu>

The ajax response is good, but simply don't work after the update:

<?xml version='1.0' encoding='UTF-8'?>
<partial-response id="j_id1"><changes><update id="B"><![CDATA[<select id="B" name="b" size="1" onchange="mojarra.ab(this,event,'valueChange','@this','C')"> <option value="">Seleccione...</option>
    <option value="BUE">Ezeiza o Aeroparque</option>
</select>]]></update><update id="j_id1:javax.faces.ViewState:0"><![CDATA[-2984590031183218074:6198891110668113457]]></update></changes></partial-response>

UPDATE!

With PrimeFaces I have the same behavior:

<h:form id="filtro">
<p:selectOneMenu id="A" value="#{paqueteBean.mes}">
    <f:selectItem itemLabel="Seleccione..." itemValue="" />
    <f:selectItem itemLabel="Enero" itemValue="ENERO" />
    <f:selectItem itemLabel="Febrero" itemValue="FEBRERO" />
    <f:selectItem itemLabel="Marzo" itemValue="MARZO" />
    <p:ajax listener="#{paqueteBean.changeMes}" update="B" />
</p:selectOneMenu>

<p:selectOneMenu id="B" value="#{paqueteBean.origen}"
    disabled="#{empty paqueteBean.mes}">
    <f:selectItem itemLabel="Seleccione..." itemValue="" />
    <f:selectItems value="#{paqueteBean.origenes}" />
    <p:ajax listener="#{paqueteBean.changeOrigen}" update="C"
        process="origen mesSalida" />
</p:selectOneMenu>

<p:selectOneMenu id="C" value="#{paqueteBean.zona}"
    disabled="#{empty paqueteBean.mes or empty paqueteBean.origen}">
    <f:selectItem itemLabel="Seleccione..." itemValue="" />
    <f:selectItems value="#{paqueteBean.zonas}" />
</p:selectOneMenu>

When I change some A values, the method in backing bean is fired, but when I change some B value, the method in backing bean is not fired.

The most strange is that for items that existed in B before the ajax update, the backing bean is called.

Backing Bean, nothing special:

    public void changeMes(){
    logger.debug("en changeMes el Mes es: " + this.mes);

    this.origenes = new HashMap<String, String>();
    this.origenes.put("Ezeiza o Aeroparque", "BUE");
}

public void changeOrigen(){
    logger.debug("Mes: " + this.mes);
    logger.debug("Origen" + this.origen);

    this.zonas = new HashMap<String, String>();
    this.zonas.put("Argentina", "AR");
    this.zonas.put("Brasil", "BR");
}

public void changeZona(){
    logger.debug("Mes: " + this.mes);
    logger.debug("Origen" + this.origen);
    logger.debug("Zona" + this.zona);

    this.destinos = new HashMap<>();
    this.destinos.put("Mar del Plata", "MDQ");
    this.destinos.put("Punta Lara", "LTA");
}

Best Answer

UPDATE:

here is a working example:

Bean:

import java.util.ArrayList;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.model.SelectItem;

@ManagedBean(name="myBean")
@SessionScoped
public class MyBean {

    private boolean bDisabled;
    private boolean cDisabled;

    private String selectedA;
    private String selectedB;
    private String selectedC;
    private ArrayList<SelectItem> aItems;
    private ArrayList<SelectItem> bItems;
    private ArrayList<SelectItem> cItems;

    public MyBean() {

    }

    @PostConstruct
    public void init(){
        try{            

            this.bDisabled = new Boolean(true);
            this.cDisabled = new Boolean(true);

            this.aItems = new ArrayList<SelectItem>();
            this.bItems = new ArrayList<SelectItem>();
            this.cItems = new ArrayList<SelectItem>();

            this.aItems.add(new SelectItem("NONE", "---?"));
            this.aItems.add(new SelectItem("A1", "A 1"));
            this.aItems.add(new SelectItem("A1", "A 1"));
            this.aItems.add(new SelectItem("A1", "A 1"));

            this.bItems.add(new SelectItem("NONE", "---?"));
            this.cItems.add(new SelectItem("NONE", "---?"));

        }catch(Exception e){
            e.printStackTrace();
        }
    }   

    public final void selectA(final AjaxBehaviorEvent event){
        try{
            System.out.println(this.selectedA);
            this.bItems.clear();
            this.bItems.add(new SelectItem("NONE", "---?"));
            if(this.selectedA.equals("NONE") ){
                this.setbDisabled(true);
                return;
            }
            this.bItems.add(new SelectItem("B1","B 1"));
            this.setbDisabled(false);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public final void selectB(final AjaxBehaviorEvent event){
        try{
            System.out.println(this.selectedB);
            this.cItems.clear();
            this.cItems.add(new SelectItem("NONE", "---?"));
            if(this.selectedB.equals("NONE") ){
                this.setcDisabled(true);
                return;
            }           
            this.cItems.add(new SelectItem("C1","C 1"));
            this.setcDisabled(false);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public final void selectC(final AjaxBehaviorEvent event){
        try{
            System.out.println(this.selectedC);
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }

    public String getSelectedA() {
        return selectedA;
    }

    public void setSelectedA(String selectedA) {
        this.selectedA = selectedA;
    }

    public String getSelectedB() {
        return selectedB;
    }

    public void setSelectedB(String selectedB) {
        this.selectedB = selectedB;
    }

    public String getSelectedC() {
        return selectedC;
    }

    public void setSelectedC(String selectedC) {
        this.selectedC = selectedC;
    }

    public ArrayList<SelectItem> getaItems() {
        return aItems;
    }

    public void setaItems(ArrayList<SelectItem> aItems) {
        this.aItems = aItems;
    }

    public ArrayList<SelectItem> getbItems() {
        return bItems;
    }

    public void setbItems(ArrayList<SelectItem> bItems) {
        this.bItems = bItems;
    }

    public ArrayList<SelectItem> getcItems() {
        return cItems;
    }

    public void setcItems(ArrayList<SelectItem> cItems) {
        this.cItems = cItems;
    }

    public boolean isbDisabled() {
        return bDisabled;
    }

    public void setbDisabled(boolean bDisabled) {
        this.bDisabled = bDisabled;
    }

    public boolean iscDisabled() {
        return cDisabled;
    }

    public void setcDisabled(boolean cDisabled) {
        this.cDisabled = cDisabled;
    }

}

XHTML:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      >
<h:head>
    <meta charset="UTF-8" />
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <title>Test</title>    
</h:head>
<body>
<f:view> 
<h:form id="dataForm">
<h:selectOneMenu value="#{myBean.selectedA}" style="width: 100%;">
    <f:selectItems value="#{myBean.aItems}" /> 
    <f:ajax execute="@form" render="@form" listener="#{myBean.selectA}" />
</h:selectOneMenu>

<h:selectOneMenu disabled="#{myBean.bDisabled}" value="#{myBean.selectedB}" style="width: 100%;">
    <f:selectItems value="#{myBean.bItems}" /> 
    <f:ajax execute="@form" render="@form" listener="#{myBean.selectB}" />
</h:selectOneMenu>

<h:selectOneMenu disabled="#{myBean.cDisabled}" value="#{myBean.selectedC}" style="width: 100%;">
    <f:selectItems value="#{myBean.cItems}" /> 
    <f:ajax execute="@form" render="@form" listener="#{myBean.selectC}" />
</h:selectOneMenu>

</h:form>
</f:view>
</body>
</html>