Event Function called before Setter

元气小坏坏 提交于 2019-12-18 05:22:13

问题


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


回答1:


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}"




回答2:


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.



来源:https://stackoverflow.com/questions/7722351/event-function-called-before-setter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!