1

I have two fields on a form that are cross validated. Initially the user see this:

enter image description here

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

enter image description here

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

enter image description here

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.

How can I get the value 2 to get resubmitted and revalidated when the user enters the 3?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
jeff
  • 3,618
  • 9
  • 48
  • 101
  • possible duplicate of [JSF doesn't support cross-field validation, is there a workaround?](http://stackoverflow.com/questions/6282466/jsf-doesnt-support-cross-field-validation-is-there-a-workaround) – DavidS May 04 '15 at 18:31
  • 1
    The problem is a slightly more complicated here by the fact that OP is doing ajax validation; it'll be necessary to ajax-process that field also – kolossus May 04 '15 at 18:40
  • Is one of these applicable as a duplicate? http://stackoverflow.com/questions/10723133/after-validation-error-subsequent-ajax-requests-get-values-from- http://stackoverflow.com/questions/14371723/input-fields-hold-previous-values-only-if-validation-failed – Kukeltje May 04 '15 at 21:12

1 Answers1

1

There are a couple of problems here:

  1. 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 via binding and use UIInput#getValue() on it instead.

  2. The <p:ajax> by default processes only the component it is nested in, as in process="@this". You really need to process the other component too in order to have the right value in the validator.

  3. 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:


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):

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

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Tried using binding, but ajax would not fire the validators in the expected order. Even though I changed the minimum value first, the validator for the max would get fired first, then the validator for the min. The values were not as expected. – jeff May 05 '15 at 14:07
  • I am using OmniFaces. I actually looked at the omnifaces validator api and saw things like validateEqual. I was looking for a validateGreaterThan. Not sure why I didn't notice validateOrder has GT, LT, etc.. Will try and post back – jeff May 05 '15 at 14:13
  • I'm in amazed once again. The validateOrder works like a charm! And it is so much cleaner. – jeff May 05 '15 at 15:00