如何在使用绑定和View范围时调用JSF验证器,valueChangeListener和actionListener,但不能多次调用

时间:2014-10-03 16:45:23

标签: jsf-2

JSF组件使用binding,支持bean为View scope。该组件设置了validatorvalueChangeListener。当组件的值改变时,部分请求被发送到服务器。 validatorvalueChangListener被多次调用,但在请求中不会被调用一次。

如何在请求期间调用它们一次?

如果删除binding,则会正确调用一次方法。

但是有可能不删除绑定并使侦听器被调用一次吗?

下一个使用的代码示例:

<h:inputText id="txt"
             validator="#{myBean.validateValue}"
             valueChangeListener="#{myBean.valueChanged}"
             binding="#{myBean.txtInput}">
   <f:ajax event="valueChange"
           execute="@this"
           render="@this"/>
</h:inputText>

@ViewScoped
@ManagedBean
public class MyBean {

private HtmlInputText txtInput;

public void valueChanged(ValueChangeEvent ve) {
    ...
}

public void validateValue(FacesContext context, UIComponent component, Object value) {
    ...
}

public HtmlTextInput getTxtInput() {
    return txtInput;
}

public void setTxtInput(HtmlTextInput txtInput) {
    this.txtInput = txtInput;
}    

}

如果actionListenercommandLink组件使用绑定且支持bean具有View scope,则会发生同样的问题。

1 个答案:

答案 0 :(得分:-1)

可能的解决方案可能只是覆盖UIInputUICommand用来存储validatorslisteners的类。该课程为javax.faces.component.AttachedObjectListHolder

此类直接将新listener添加到支持列表,而不检查是否已存在相同的listener。 因此,解决方案是检查listener是否存在,然后不添加它。

javax.faces.component.AttachedObjectListHolder获取jsf-api-2.1.<x>-sources.jar并将其添加到项目中的相应包中。将方法add替换为以下方法:

void add(T attachedObject) {
    boolean addAttachedObject = true;

    if (attachedObject instanceof MethodExpressionActionListener
        || attachedObject instanceof MethodExpressionValueChangeListener
        || attachedObject instanceof MethodExpressionValidator) {

        if (attachedObjects.size() > 0) {
            StateHolder listener = (StateHolder) attachedObject;
            FacesContext context = FacesContext.getCurrentInstance();
            Object[] state = (Object[]) listener.saveState(context);
            Class<? extends StateHolder> listenerClass = listener.getClass();

            for (Object tempAttachedObject : attachedObjects) {
                if (listenerClass.isAssignableFrom(tempAttachedObject.getClass())) {
                    Object[] tempState = (Object[]) ((StateHolder) tempAttachedObject).saveState(context);
                    if (((MethodExpression) state[0]).getExpressionString().equals(((MethodExpression)tempState[0]).getExpressionString())) {
                        addAttachedObject = false;
                        break;
                    }
                }
            }
        }
    }

    clearInitialState();
    if (addAttachedObject) {
        attachedObjects.add(attachedObject);
    }
}

在验证器之后,即使使用组件绑定和“查看”,“会话”或“应用程序”范围,valueChangeListeners和actionListeners也只会触发一次。