问题描述
我今天正在寻找有关我遇到的问题的一些指导.
我想要完成的是即时构建一个带有验证和所有功能的页面.最终结果是允许用户通过管理功能配置页面上的字段.下面是我用作测试页的代码副本,我在其中循环已配置"字段并使用定义的条件写出字段.
<div class="formLabel"><h:outputLabel value="#{field.customName}:"></h:outputLabel>
我今天正在寻找有关我遇到的问题的一些指导.
我想要完成的是即时构建一个带有验证和所有功能的页面.最终结果是允许用户通过管理功能配置页面上的字段.下面是我用作测试页的代码副本,我在其中循环已配置"字段并使用定义的条件写出字段.
<div class="formLabel"><h:outputLabel value="#{field.customName}:"></h:outputLabel>
<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>
</ui:repeat>
页面呈现后,我尝试为该字段提交任何值,我收到以下消息Regex 模式必须设置为非空值."这显然意味着没有填充表达式.令我感兴趣的是,当评估 EL 时,没有表达式的字段将被禁用.我也可以将相同的代码#{field.validationPattern} 放在页面中,正确的值就会写在页面上.
所以,我的问题是:1. 这可能吗?2. JSF 容器在什么时候考虑绑定验证正则表达式的模式?3. 我做错了什么或这样做的正确方法是什么??
我正在运行 Tomcat 7.0.22、Mojarra 2.1.5 和 Eclipse 作为我的 IDE.
这是由于使用了 导致的,其属性依赖于当前迭代的
.
标签是标签处理程序,而不是 UI 组件.在视图构建期间构建 UI 组件树时,会解析和评估标记处理程序.在视图构建期间评估所有 EL.
标签和一些
标签,如
是 UI 组件.他们所有的 EL 都会在视图渲染期间进行评估.
所以在你的情况下,当 被解析和执行时,
#{field}
在当前 EL 范围内不可用,因此评估作为 null
.
有几种方法可以让它工作.
将验证器移动到表示 Field
的类,并按如下方式引用它:
<h:inputText ... validator="#{field.validate}"/>
在 Field
类中手动实例化它:
public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {如果(模式!= null){RegexValidator regexValidator = new RegexValidator();regexValidator.setPattern(pattern);regexValidator.validate(上下文,组件,值);}}
或者,将 #{eventMgmt.eventFields}
包裹在 ListDataModel
中,并将验证器绑定到 #{eventMgmt}
代码>豆.这样您就可以根据行数据设置验证器的属性:
<h:inputText ... validator="#{eventMgmt.validate}"/>
在 #{eventMgmt}
后面的支持 bean 类中:
私有数据模型模型;私人 RegexValidator regexValidator;@PostConstruct公共无效初始化(){regexValidator = new RegexValidator();}公共无效验证(FacesContext 上下文,UIComponent 组件,对象值)抛出 ValidatorException {字符串模式 = model.getRowData().getPattern();如果(模式!= null){regexValidator.setPattern(pattern);regexValidator.validate(上下文,组件,值);}}
或者,创建一个自定义的 Validator
扩展 RegexValidator
并通过 将模式设置为组件的自定义属性;
并让 Validator
拦截它. 基本上是给组件添加了一个新的属性,带有一个未求值的
ValueExpression
,所以在调用的时候会重新求值.例如:
<f:validator validatorId="extendedRegexValidator"/><f:attribute name="pattern" value="#{field.pattern}"/></h:inputText>
与
@FacesValidator("extendedRegexValidator")公共类 ExtendedRegexValidator 扩展 RegexValidator {@覆盖公共无效验证(FacesContext 上下文,UIComponent 组件,对象值)抛出 ValidatorException {String pattern = (String) component.getAttributes().get("pattern");如果(模式!= null){设置模式(模式);super.validate(上下文,组件,值);}}}
或者,如果您碰巧使用 JSF 实用程序库 OmniFaces,请使用其 .例如
<o:validator validatorId="javax.faces.RegularExpression" pattern="#{field.pattern}"/></h:inputText>
是的,仅此而已. 将确保所有属性都被评估为延迟表达式而不是立即表达式.
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.
这篇关于使用基于 ui:repeat var 的 EL 设置验证器属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!