为什么要调用未更改组件的验证器?

时间:2010-05-11 16:27:36

标签: jsf validation icefaces

我有一个IceFaces表单和几个输入字段。

假设我有这个:

<ice:selectOneMenu id="accountMenu"
    value="#{accountController.account.aId}"
    validator="#{accountController.validateAccount}">
    <f:selectItems id="accountItems"
            value="#{accountController.accountItems}" />
</ice:selectOneMenu>

和此:

<ice:selectOneMenu id="costumerMenu"
    value="#{customerController.customer.cId}"
    validator="#{customerController.validateCustomer">
    <f:selectItems id="customerItems"
            value="#{customerController.customerItems}" />
</ice:selectOneMenu>

如果我改变一个值,则会调用相应的验证器,这没什么问题。但也调用了另一个验证器,这是不好的,因为用户得到一个令人恼火的消息,将值插入他可能只是要注意的字段。这就像用一根棍子向“用户快点!”戳戳用户。 BAD!

我认为属性“partialSubmit”正在控制这种行为,所以只提交了一个DOM-part,它受到用户交互的影响,但是如果我声明两个组件都被部分提交,则没有任何变化。如果更改了一个组件值,则仍会调用两个验证器。

如何在完全提交之前阻止整个表单的验证?

2 个答案:

答案 0 :(得分:5)

执行部分提交时,仍会执行完整的JSF生命周期。因此,仍然会处理验证阶段,并验证组件层次结构中的所有组件。

这有充分的理由。一个组件的更改可能会导致另一个组件发生(可能无效)更改。例如,selectOneMenu中的选择可以设置inputText中的值。

ICEfaces以一种显着的方式改变处理:在部分提交期间,ICEfaces临时将除触发sumbit的组件之外的所有组件标记为可选(required="false")。因此,跳过“必需”验证。但是,ICEfaces不会禁用其他验证。

这个问题有两种可能的解决方案:

  1. 除了immediate="true"之外还设置partialSubmit。当执行部分提交以在应用请求值阶段执行验证时,这会稍微更改组件的生命周期。这可能会导致跳过其他验证。

  2. 检测您的自定义验证程序中是否发生了部分提交。如果验证不是触发部分提交的组件,则跳过验证。不幸的是,没有关于如何检测部分提交的任何文档,但我在com.icesoft.faces.application.PartialSubmitPhaseListener类的源代码中找到了解决方案。

    事实证明,ICEfaces在执行部分提交时添加了两个请求参数:

    • ice.submit.partial - 设置为“true”表示已完成部分提交。
    • ice.event.captured - 包含生成部分提交的组件的组件ID。
  3. 您可以在验证方法中利用这两个参数。这是一个例子:

    public void validateAccount(FacesContext context, 
      UIComponent component, Object value) 
    {
      if(!partiallySubmitted(context) || 
         componentWasPartiallySubmitted(context, component)
        // Perform validation
      }
    
    }
    
    public boolean partiallySubmitted(FacesContext context) {
        ExternalContext externalContext = context.getExternalContext();
        Map parameterMap = externalContext.getRequestParameterMap();   
    
        return "true".equals(parameterMap.get("ice.submit.partial"));
    }
    
    public boolean componentWasPartiallySubmitted(FacesContext context, 
      UIComponent component) {
        ExternalContext externalContext = context.getExternalContext();
        Map parameterMap = externalContext.getRequestParameterMap();   
    
        String componentId = (String) parameterMap.get("ice.event.captured");
    
        return component.getClientId(context).equals(componentId);
    }
    

    当然,可能不支持直接访问这两个请求参数。但是,在ICEfaces团队提供支持的方式来“检测”部分提交之前,它可能是您唯一的选择。

答案 1 :(得分:0)

尝试在onblur事件上执行ajax验证(不知道如何使用icefaces,但使用richfaces它只是<a4j:support event="onblur" />