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

发布于 2025-01-03 10:56:19 字数 1086 浏览 2 评论 0 原文

我今天正在针对我遇到的问题寻求一些指导。

我想要完成的是通过验证等来动态构建一个页面。最终结果是允许用户通过管理功能配置页面上的字段。下面是我用作测试页面的代码副本,我在其中循环遍历“已配置”字段并使用定义的条件写出字段。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

听你说爱我 2025-01-10 10:56:19

这是由于使用 导致的,其属性取决于 当前迭代的项目。

标记是标记处理程序,而不是 UI 组件。当要在视图构建期间构建 UI 组件树时,将解析和评估标记处理程序。所有 EL 都会在视图构建期间进行评估。 标签和一些 标签(如 )是 UI 组件。它们的所有 EL 都会在视图渲染期间进行评估。

因此,在您的情况下,当解析并执行 时,#{field} 在当前 EL 范围内不可用,因此计算结果为

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

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

    
    

    Field 类中手动实例化它:

    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        如果(模式!= null){
            RegexValidator regexValidator = new RegexValidator();
            regexValidator.setPattern(模式);
            regexValidator.validate(上下文、组件、值);
        }
    }
    

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

    
    

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

    私有 DataModel;模型;
    私有 RegexValidator regexValidator;
    
    @PostConstruct
    公共无效初始化(){
        regexValidator = 新 RegexValidator();
    }
    
    公共无效验证(FacesContext上下文,UIComponent组件,对象值)抛出ValidatorException {
        字符串模式 = model.getRowData().getPattern();
    
        如果(模式!= null){
            regexValidator.setPattern(模式);
            regexValidator.validate(上下文、组件、值);
        }
    }
    

  • 或者,创建一个自定义 Validator 扩展了 RegexValidator 并通过 将模式设置为组件的自定义属性,并让 Validator 拦截那。 基本上使用未计算的 ValueExpression 向组件添加一个新属性,因此当您调用它时它将重新计算。例如:

    ;
        >
        
    
    

    @FacesValidator("extendedRegexValidator")
    公共类 ExtendedRegexValidator 扩展 RegexValidator {
    
        @覆盖
        公共无效验证(FacesContext上下文,UIComponent组件,对象值)抛出ValidatorException {
            String Pattern = (String) component.getAttributes().get("pattern");
    
            如果(模式!= null){
                设置模式(模式);
                super.validate(上下文、组件、值);
            }
        }
    
    }
    

  • 或者,如果您碰巧使用 JSF 实用程序库 OmniFaces,请使用它的 。例如

    ;
        />
    
    

    是的,就是这样。 将确保所有属性都被计算为延迟表达式而不是立即表达式。

另请参阅:

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:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文