如何解决当用户想要覆盖JSF表单验证时,跳过特定的验证器进行第二次提交
我正在使用两个验证器来验证用户输入的帐号,一个用于基本标准格式,另一个用于根据数据库中存储的值来验证帐号。有效帐号的数据库可能并不总是最新的,因此我希望允许用户覆盖并提交其输入的帐号,但仅在数据库验证失败后才能进行。我一直想验证其标准格式8个字符,没有空格。
<h:form id="formId">
<p:panelGrid>
<p:row>
<p:column>
<p:outputLabel value="Account : " for="acct" />
</p:column>
<p:column>
<p:selectOneMenu id="acct" value="#{bean.acct.acctNum}" effect="fold" editable="true" validator="acctLengthAndSpaceValidator" required="true" requiredMessage="Required">
<f:selectItems value="#{bean.mySavedAccounts}" var="acct"
itemLabel="#{acct.acctNumber} itemValue="#{acct.acctNumber}" />
<o:validator validatorId="accountDatabaseValidator" disabled="#{bean.skipDbValidation}" />
</p:selectOneMenu>
</p:column>
<p:column>
<p:messages for="acct" showDetail="true" skipDetailIfEqualsSummary="true" />
</p:column>
</p:row>
</p:panelGrid>
<br />
<p:selectBooleanCheckbox rendered="#{facesContext.validationFailed}" value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid,please skip validation and let me submit!">
<p:ajax update="@this" listener="#{bean.testListener()}" />
</p:selectBooleanCheckbox>
<p:commandButton value="Submit" action="#{bean.submit()}" update="formId"/>
</h:form>
此复选框确实在最初提交表单后出现,并且有任何验证失败(我将找出如何仅将失败的accountDatabaseValidator隔离出来)。但是,当我选中该复选框并再次提交时,两个验证器仍然被触发。我添加了ajax侦听器进行调试,但它没有触发,并且布尔值skipDbValidation
仍然为false。
在实现针对数据库进行验证的具体目标时,我的方法也许是不正确的,但是在初始失败后,让用户可以选择跳过db验证。
编辑
如果我从复选框中删除了rendered="#{facesContext.validationFailed}"
并一直可见,则如果选中此复选框,则布尔值skipDbValidation
会设置为true,然后在后续提交时,skipDbValidation
会被忽略如预期的那样。但我不希望允许用户首先跳过可见的复选框。只有在验证失败之后。
解决方法
对此不起作用的技术解释是在处理表单提交期间重新评估了rendered
属性。此时,faces上下文不再validationFailed
(在上一个请求中仅为validationFailed
),因此不再渲染组件,因此将不会应用组件的提交值。这与commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated中的#6相匹配。
您可以通过在客户端而不是服务器端进行渲染来解决问题。但是我认为您只想在调用特定的验证器时才显示它。至少有两种方法可以实现此目的:
-
检查
UIInput#isValid()
中感兴趣的输入部分。您可以通过组件的binding
属性将组件绑定到视图(而不是bean!)上,从而在同一视图的其他地方引用它。<p:selectOneMenu binding="#{acct}" ...> ... </p:selectOneMenu> ... <p:selectBooleanCheckbox styleClass="#{acct.valid ? 'ui-helper-hidden' : ''}" ...> ... </p:selectBooleanCheckbox>
请注意,我借此机会重用了PrimeFaces提供的样式类。
-
或者,使验证器成为视图范围的bean,并改为通过
<o:validator binding>
进行引用。@Named @ViewScoped public class AccountDatabaseValidator implements Validator,Serializable { private boolean validationFailed; @Override public void validate(FacesContext context,UIComponent component,Object value) throws ValidatorException { // ... validationFailed = !isValid(value); if (validationFailed) { throw new ValidatorException(createError("Invalid value")); } } public boolean isValidationFailed() { return validationFailed; } }
<p:selectOneMenu ...> <o:validator binding="#{accountDatabaseValidator}" ... /> </p:selectOneMenu> ... <p:selectBooleanCheckbox rendered="#{accountDatabaseValidator.validationFailed}" ...> ... </p:selectBooleanCheckbox>
我的工作是使复选框以编程方式显示,因此该复选框的功能是使用CSS而不是render属性来隐藏和显示。
style="#{facesContext.validationFailed ? 'Display: inline' : 'Display: none;'}"
<p:selectBooleanCheckbox style="#{facesContext.validationFailed ? 'Display: inline' : 'Display: none;'}" value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid,please skip validation and let me submit!">
<p:ajax update="@this" />
</p:selectBooleanCheckbox>
但是我仍然不知道如何显示特定验证失败的复选框。
我将为此发布另一个问题
编辑 这就是我仅在无效帐户验证失败后才显示复选框的方式。
<p:selectBooleanCheckbox style="#{facesContext.messageList.stream()
.anyMatch(v -> v.summary == 'Invalid Account') or
bean.skipDbValidation ? 'Display: inline' : 'Display: none;'}"
value="#{bean.skipDbValidation}" itemLabel="I know this account is really valid,please skip validation and let me submit!">
<p:ajax update="@this" />
</p:selectBooleanCheckbox>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。