使用基于ui:repeat var的EL设置验证器属性 [英] Setting a validator attribute using EL based on ui:repeat var

查看:120
本文介绍了使用基于ui:repeat var的EL设置验证器属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在就遇到的问题寻求一些指导.

我要完成的工作是动态地建立一个包含验证和全部内容的页面.最终结果是允许用户通过管理功能配置页面上的字段.下面是我用作测试页的代码的副本,在该页面中,我循环浏览已配置"字段,并使用定义的条件写出这些字段.

<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}并将其放在页面中,并将正确的值写在页面上.

所以,我的问题是: 1.这可能吗? 2. JSF容器在什么时候考虑将模式绑定到验证正则表达式? 3.我做错了什么或正确的方法是做什么?

我正在将Tomcat 7.0.22,Mojarra 2.1.5和Eclipse作为我的IDE.

解决方案

这是由于使用其属性取决于<ui:repeat>的当前迭代项的<f:validateRegex>引起的.

<f:xxx>标签是标签处理程序,而不是UI组件.在视图构建期间构建UI组件树时,将解析和评估标记处理程序.在视图构建期间将评估所有EL. <h:xxx>标签和某些<ui:xxx>标签(例如<ui:repeat>)是UI组件.他们的所有EL都会在视图渲染期间进行评估.

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

有几种方法可以使其正常工作.

  • 将验证器移动到表示Field的类,并按如下所示引用它:

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

    with在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);
        }
    }
     


  • 或者,创建一个扩展了RegexValidator的自定义Validator,并通过<f:attribute>将模式设置为组件的自定义属性,然后让Validator对其进行拦截. <f:attribute>基本上是使用未评估的ValueExpression向组件添加新属性,因此在调用它时将对其进行重新评估.例如:

     <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>将确保所有属性都被评估为延迟表达式,而不是立即表达式.

另请参见:

I am looking for a little bit of guidance today with the issue I am running into.

What I am trying to accomplish is build a page on the fly with validation and all. The end result is to allow the user to configure the fields on the page through administrative functions. Below is a copy of the code that I am using as the test page where I loop through the "Configured" fields and write out the fields using the defined criteria.

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

After the page renders and I attempt to submit any values for the field, I get the following message "Regex pattern must be set to non-empty value." which obviously means that the expression is not populated. What makes it interesting to me is that fields that do not have an expression for them will be disabled when the EL is evaluated. I can also take the same code #{field.validationPattern} and put it in the page and the correct value will be written on the page.

So, my question(s) are: 1. Is this possible? 2. At what point does the JSF container look at binding the Pattern for the validate regex? 3. What am I doing wrong or What is the right way to do this ??

I am running Tomcat 7.0.22, Mojarra 2.1.5, and Eclipse as my IDE.

解决方案

This is caused by using <f:validateRegex> whose properties depend on the currently iterated item of <ui:repeat>.

The <f:xxx> tags are tag handlers, not UI components. Tag handlers are parsed and evaluated when the UI component tree is to be built during view build time. All EL is evaluated during the view build time. The <h:xxx> tags and some <ui:xxx> tags like <ui:repeat> are UI components. All their EL is evaluated during view render time.

So in your case, when <f:validateRegex> get parsed and executed, the #{field} is not available in the current EL scope and thus evaluates as null.

There are several ways to get it to work.

  • Move the validator to the class representing Field and reference it as follows:

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

    with in Field class wherein you manually instantiate it:

    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);
        }
    }
    


  • Or, wrap #{eventMgmt.eventFields} in a ListDataModel<Field> and bind the validator to the #{eventMgmt} bean. This way you will be able to set the validator's properties based on the row data:

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

    with in the backing bean class behind #{eventMgmt}:

    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);
        }
    }
    


  • Or, create a custom Validator which extends RegexValidator and set the pattern as a custom attribute of the component by <f:attribute> and let the Validator intercept on that. The <f:attribute> basically adds a new attribute to the component with an unevaluated ValueExpression, so it will be re-evaluated when you call it. E.g.:

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

    with

    @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);
            }
        }
    
    }
    


  • Or, if you happen to use JSF utility library OmniFaces, use its <o:validator>. E.g.

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

    Yes, that's all. The <o:validator> will make sure that all attributes are evaluated as deferred expressions instead of immediate expressions.

See also:

这篇关于使用基于ui:repeat var的EL设置验证器属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆