I have two fields on a form that are cross validated. Initially the user see this:
我在表单上有两个交叉验证的字段。最初用户看到这个:
<p:inputText size="5"
value="#{bean.maximum_hole_diameter}">
<f:validator validatorId="doubleNotLessThanSecondDouble" />
<f:attribute name="secondDouble"
value="#{bean.minimum_hole_diameter}" />
<p:ajax event="change" update="@this" />
</p:inputText>
<p:inputText size="5"
value="#{bean.minimum_hole_diameter}">
<f:validator validatorId="doubleNotGreaterThanSecondDouble" />
<f:attribute name="secondDouble"
value="#{bean.maximum_hole_diameter}" />
<p:ajax event="change" update="@this" />
</p:inputText>
Everything works as expected IF the user enters a positive value for the maximum first and then a lesser value for the minimum.
如果用户首先输入最大值的正值,然后输入最小值的较小值,则一切都按预期工作。
If they enter the minimum first that gets flagged as invalid:
如果他们输入被标记为无效的最小值:
So far so good - 2 is larger than 0.0. Intuitively, the user would then put in a maximum hole diameter, which is larger than the minimum. But the form get's stuck. The minimum is still invalid because technically in the model it is still 0.0. Ajax never stored the value 2 in the model but the browser still shows the value 2. How can I get the 2 to get revalidated and stored in my bean??
到目前为止一直很好 - 2大于0.0。直观地,用户然后将放入最大孔直径,该孔直径大于最小值。但表格被卡住了。最小值仍然无效,因为在模型中技术上它仍然是0.0。 Ajax从未在模型中存储值2,但浏览器仍显示值2.如何才能让2重新验证并存储在我的bean中?
I could do a update="@form" to clear the 2 value back to zero but this would frustrate the user. And if the user retypes 2, the form doesn't get submitted, because the it hasn't "changed". The user has to change to another number then go back to 2. Doing "onblur" has its issues too.
我可以执行update =“@ form”将2值清零,但这会让用户感到沮丧。如果用户重新输入2,表单不会被提交,因为它没有“改变”。用户必须更改为另一个号码,然后返回2.执行“onblur”也有问题。
How can I get the value 2 to get resubmitted and revalidated when the user enters the 3?
当用户输入3时,如何获取值2以重新提交并重新验证?
1 个解决方案
#1
There are a couple of problems here:
这里有几个问题:
-
You're in
<f:attribute>
passing the model value to the validator instead of the component value. The updated model value is not necessarily available during Validations phase, which runs before Update Model Values phase. It will only work if the input field referencing this model value was successfully processed in a previous request. You'd better pass the physical component along which is referenced viabinding
and useUIInput#getValue()
on it instead.您在
中将模型值传递给验证器而不是组件值。验证阶段不一定可以使用更新的模型值,验证阶段在更新模型值阶段之前运行。只有在先前的请求中成功处理了引用此模型值的输入字段时,它才会起作用。您最好传递通过绑定引用的物理组件,并在其上使用UIInput#getValue()。 -
The
<p:ajax>
by default processes only the component it is nested in, as inprocess="@this"
. You really need to process the other component too in order to have the right value in the validator.默认情况下,
仅处理嵌套的组件,如process =“@ this”。您确实需要处理其他组件,以便在验证器中具有正确的值。 -
You're not updating the other input when changing one input. So the other input will never be able to remove the error highlight when validation on it actually succeeds.
更改一个输入时,您不会更新其他输入。因此,当其验证实际成功时,其他输入将永远无法删除错误突出显示。
All in all, this should do it:
总而言之,这应该做到:
<p:inputText id="max" binding="#{max}" ...>
<f:validator validatorId="doubleNotLessThanSecondDouble" />
<f:attribute name="secondComponent" value="#{min}" />
<p:ajax process="@this min" update="@this min" />
</p:inputText>
<p:inputText id="min" binding="#{min}" ...>
<f:validator validatorId="doubleNotGreaterThanSecondDouble" />
<f:attribute name="secondComponent" value="#{max}" />
<p:ajax process="@this max" update="@this max" />
</p:inputText>
With below logic in those validators:
在这些验证器中使用以下逻辑:
double firstDouble = (double) value;
UIInput secondComponent = (UIInput) component.getAttributes().get("secondComponent");
double secondDouble = (double) secondComponent.getValue();
// ...
See also:
- JSF doesn't support cross-field validation, is there a workaround?
- Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
- What is component binding in JSF? When it is preferred to be used?
JSF不支持跨领域验证,是否有解决方法?
了解PrimeFaces进程/更新和JSF f:ajax执行/呈现属性
什么是JSF中的组件绑定?何时优先使用?
If you happen to use JSF utility library OmniFaces, or are open to using it, then it's good to know that this requirement is also covered by <o:validateOrder>
as below (without need for any custom validator):
如果您碰巧使用JSF实用程序库OmniFaces,或者打开使用它,那么很高兴知道此要求也包含在
<h:panelGroup id="diameter">
<p:inputText id="max" ...>
<p:ajax process="diameter" update="diameter" />
</p:inputText>
<p:inputText id="min" ...>
<p:ajax process="diameter" update="diameter" />
</p:inputText>
<o:validateOrder type="gt" components="max min" />
</h:panelGroup>
Unrelated to the concrete problem, you'd better use BigDecimal
instead of double
if accuracy is that important.
与具体问题无关,如果准确性很重要,最好使用BigDecimal而不是double。
#1
There are a couple of problems here:
这里有几个问题:
-
You're in
<f:attribute>
passing the model value to the validator instead of the component value. The updated model value is not necessarily available during Validations phase, which runs before Update Model Values phase. It will only work if the input field referencing this model value was successfully processed in a previous request. You'd better pass the physical component along which is referenced viabinding
and useUIInput#getValue()
on it instead.您在
中将模型值传递给验证器而不是组件值。验证阶段不一定可以使用更新的模型值,验证阶段在更新模型值阶段之前运行。只有在先前的请求中成功处理了引用此模型值的输入字段时,它才会起作用。您最好传递通过绑定引用的物理组件,并在其上使用UIInput#getValue()。 -
The
<p:ajax>
by default processes only the component it is nested in, as inprocess="@this"
. You really need to process the other component too in order to have the right value in the validator.默认情况下,
仅处理嵌套的组件,如process =“@ this”。您确实需要处理其他组件,以便在验证器中具有正确的值。 -
You're not updating the other input when changing one input. So the other input will never be able to remove the error highlight when validation on it actually succeeds.
更改一个输入时,您不会更新其他输入。因此,当其验证实际成功时,其他输入将永远无法删除错误突出显示。
All in all, this should do it:
总而言之,这应该做到:
<p:inputText id="max" binding="#{max}" ...>
<f:validator validatorId="doubleNotLessThanSecondDouble" />
<f:attribute name="secondComponent" value="#{min}" />
<p:ajax process="@this min" update="@this min" />
</p:inputText>
<p:inputText id="min" binding="#{min}" ...>
<f:validator validatorId="doubleNotGreaterThanSecondDouble" />
<f:attribute name="secondComponent" value="#{max}" />
<p:ajax process="@this max" update="@this max" />
</p:inputText>
With below logic in those validators:
在这些验证器中使用以下逻辑:
double firstDouble = (double) value;
UIInput secondComponent = (UIInput) component.getAttributes().get("secondComponent");
double secondDouble = (double) secondComponent.getValue();
// ...
See also:
- JSF doesn't support cross-field validation, is there a workaround?
- Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
- What is component binding in JSF? When it is preferred to be used?
JSF不支持跨领域验证,是否有解决方法?
了解PrimeFaces进程/更新和JSF f:ajax执行/呈现属性
什么是JSF中的组件绑定?何时优先使用?
If you happen to use JSF utility library OmniFaces, or are open to using it, then it's good to know that this requirement is also covered by <o:validateOrder>
as below (without need for any custom validator):
如果您碰巧使用JSF实用程序库OmniFaces,或者打开使用它,那么很高兴知道此要求也包含在
<h:panelGroup id="diameter">
<p:inputText id="max" ...>
<p:ajax process="diameter" update="diameter" />
</p:inputText>
<p:inputText id="min" ...>
<p:ajax process="diameter" update="diameter" />
</p:inputText>
<o:validateOrder type="gt" components="max min" />
</h:panelGroup>
Unrelated to the concrete problem, you'd better use BigDecimal
instead of double
if accuracy is that important.
与具体问题无关,如果准确性很重要,最好使用BigDecimal而不是double。