使用基于ui:repeat var的EL设置验证器属性

时间:2012-02-08 14:06:09

标签: validation jsf-2 el uirepeat

我正在寻找一些关于我遇到的问题的指导。

我要完成的是通过验证和所有内容动态构建页面。最终结果是允许用户通过管理功能配置页面上的字段。下面是我用作测试页面的代码的副本,我在其中循环“已配置”字段并使用定义的标准写出字段。

<ui:repeat var="field" value="#{eventMgmt.eventFields}" varStatus="status">
  <div class="formLabel">
    <h:outputLabel value="#{field.customName}:"></h:outputLabel>
  </div>
  <div class="formInput">
    <h:inputText id="inputField" style="width:# {field.fieldSize gt 0 ? field.fieldSize : 140}px;">
      <f:validateRegex  disabled="#{empty field.validationPattern}" pattern="#{field.validationPattern}"></f:validateRegex>
    </h:inputText>
    <h:message for="inputField" showDetail="true" errorClass="errorText"></h:message>
  </div>
</ui:repeat>

页面渲染后,我尝试提交字段的任何值,我收到以下消息“必须将正则表达式模式设置为非空值”。这显然意味着表达式没有填充。让我感兴趣的是,在评估EL时,将禁用没有表达式的字段。我也可以使用相同的代码#{field.validationPattern}并将其放在页面中,并在页面上写入正确的值。

所以,我的问题是:   这有可能吗?   2. JSF容器在什么时候看看绑定Pattern for validate regex?   3.我做错了什么或做这件事的正确方法是什么?

我正在运行Tomcat 7.0.22,Mojarra 2.1.5和Eclipse作为我的IDE。

1 个答案:

答案 0 :(得分:12)

这是因为使用<f:validateRegex>,其属性取决于当前迭代的<ui:repeat>项。

<f:xxx>标记是标记处理程序,而不是UI组件。在视图构建期间构建UI组件树时,将解析和评估标记处理程序。在视图构建期间评估所有EL。 <h:xxx>标记和<ui:xxx>标记(如<ui:repeat>)是UI组件。在视图渲染时间内评估它们的所有EL。

因此,在您的情况下,当<f:validateRegex>被解析并执行时,#{field}在当前EL范围内不可用,因此评估为null

有几种方法可以让它发挥作用。

  • 将验证器移至代表Field的类,并按如下方式引用它:

    <h:inputText ... validator="#{field.validate}" />
    

    Field类中,您手动实例化它:

    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (pattern != null) {
            RegexValidator regexValidator = new RegexValidator();
            regexValidator.setPattern(pattern);
            regexValidator.validate(context, component, value);
        }
    }
    

  • 或者,将#{eventMgmt.eventFields}包装在ListDataModel<Field>中,并将验证器绑定到#{eventMgmt} bean。这样,您就可以根据行数据设置验证器的属性:

    <h:inputText ... validator="#{eventMgmt.validate}" />
    

    #{eventMgmt}后面的支持bean类中:

    private DataModel<Field> model;
    private RegexValidator regexValidator;
    
    @PostConstruct
    public void init() {
        regexValidator = new RegexValidator();
    }
    
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String pattern = model.getRowData().getPattern();
    
        if (pattern != null) {
            regexValidator.setPattern(pattern);
            regexValidator.validate(context, component, value);
        }
    }
    

  • 或者,创建一个扩展Validator的自定义RegexValidator,并将模式设置为<f:attribute>组件的自定义属性,然后Validator拦截那。 <f:attribute>基本上为具有未评估ValueExpression的组件添加了新属性,因此在您调用它时将重新评估它。 E.g:

    <h:inputText ...>
        <f:validator validatorId="extendedRegexValidator" />
        <f:attribute name="pattern" value="#{field.pattern}" />
    </h:inputText>
    

    @FacesValidator("extendedRegexValidator")
    public class ExtendedRegexValidator extends RegexValidator {
    
        @Override
        public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
            String pattern = (String) component.getAttributes().get("pattern");
    
            if (pattern != null) {
                setPattern(pattern);
                super.validate(context, component, value);
            }
        }
    
    }
    

  • 或者,如果您碰巧使用JSF实用程序库OmniFaces,请使用其<o:validator>。 E.g。

    <h:inputText ...>
        <o:validator validatorId="javax.faces.RegularExpression" pattern="#{field.pattern}" />
    </h:inputText>
    

    是的,就是这样。 <o:validator>将确保将所有属性评估为延迟表达式而不是立即表达式。

另见: