我今天正在寻找一些关于我遇到的问题的指导。
我试图完成的是动态构建一个带有验证和所有内容的页面。 最终结果是允许用户通过管理功能配置页面上的字段。 下面是我用作测试页面的代码副本,我在其中循环浏览"已配置"字段并使用定义的条件写出字段。
<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}" />
在
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>
。<h:inputText ...> <o:validator validatorId="javax.faces.RegularExpression" pattern="#{field.pattern}" /> </h:inputText>
是的,仅此而已。
<o:validator>
将确保将所有属性计算为延迟表达式而不是直接表达式。
另请参阅:
- 如何为数据表的每一行设置转换器属性?