ke3pup
ke3pup

Reputation: 1895

Event Function called before Setter

I have the following dropdown which list couple of cars, I have it so that it stores the value of selected item in a backbean variable and an event is fired so other dropdowns would fill up according to the selected value of this dropdown control as below:

  <Td>
<h:selectOneMenu id="combocarList" 
    value="#{customerBean.selectedcar}"
    styleClass="comboStyle"
    valueChangeListener="#{customerBean.loadothercombos}"
    onchange="document.forms[0].submit()"
    >
    <f:selectItem
        itemLabel="-----------Select--------------"
        itemValue="None" />
    <f:selectItems value="#{customerBean.carsList}" />
</h:selectOneMenu>
 </Td>

Problem is when an item selected from the above dropdown, the event loadothercombos is called before the setter which causes problems.

Note that the backbean customer is defined as:

 <managed-bean-name>customerBean</managed-bean-name>
    <managed-bean-class>com.theway.customer</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>

The behaviour i see in debugging that when i select an item from dropdown:

1) Getter is called for selectedcar
2) Loadothercombos is called  <------- This is called by the event
3) Setter is called for selectedcar

I cannot get it to call the setter before calling loadothercombos. Any insight would be appreciated. Thanks

Upvotes: 3

Views: 4237

Answers (2)

BalusC
BalusC

Reputation: 1108632

Using valueChangeListener for this purpose has always been a hacky way. Basically, there are two ways to work around this "problem":

  1. Call FacesContext#renderResponse() so that JSF will immediately move to the render response phase and thus the update model values (and invoke action) phase will be skipped:

    public void loadothercombos(ValueChangeEvent event) {
        selectedcar = (String) event.getNewValue();
        loadOtherCombosBasedOn(selectedcar);
        // ...
    
        FacesContext.getCurrentInstance().renderResponse();
    }
    
  2. Queue the event to invoke action phase so that it does its job after the setter being called:

    public void loadothercombos(ValueChangeEvent event) {
        if (event.getPhaseId() == PhaseId.INVOKE_APPLICATION) {
            loadOtherCombosBasedOn(selectedcar);
        } else {
            event.setPhaseId(PhaseId.INVOKE_APPLICATION);
            event.queue();
        }
    }
    

If you're using JSF 2.0, then there's a much easier way to handle this with help of <f:ajax>:

<h:selectOneMenu id="combocarList" 
    value="#{customerBean.selectedcar}"
    styleClass="comboStyle">
    <f:selectItem
        itemLabel="-----------Select--------------"
        itemValue="None" />
    <f:selectItems value="#{customerBean.carsList}" />
    <f:ajax listener="#{customerBean.loadOtherCombos}" render="otherComboIds" />
</h:selectOneMenu>

with

public void loadothercombos() {
    loadOtherCombosBasedOn(selectedcar);
}

Unrelated to the concrete problem: a "combobox" is the incorrect term for this dropdown element. A combobox is an editable dropdown, it's basically a combination of <input type="text"> and <select>. What you've there just renders alone <select> and those are just dropdowns, so call them as such as well.

Upvotes: 8

Victor Martinez
Victor Martinez

Reputation: 1112

Problem is when an item selected from the above dropdown, the event loadothercombos is called before the setter

Well, is the expected JSF life cycle behavior. Your valueChangeListener="#{customerBean.loadothercombos}" is invoked during validation phase after a succesful conversion/validation of the submitted value and only when the submitted value differs from the initial value. After invoking the valueChangeListener, JSF will continue with conversion/validation of the next UIInput and when JSF implementation determines that the data is valid, then proceed to the next Update Model Values Phase invoking your setter method value="#{customerBean.selectedcar}"

Upvotes: 1

Related Questions