I have two PrimeFaces selectOneMenu components. When the first component is set to a certain value, I need the second component to become required. I use Ajax and binding to update the second component when the first is submitted, so that the user sees the required '*' next to the second component's label. That part is easy.
Here is the (somewhat simplified) code:
<p:outputLabel id="foolbl" for="foo"
value="Foo" />
<p:selectOneMenu id="foo" required="true"
value="#{bean.foo}" binding="#{foobnd}">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
value="#{bean.foovalues}" />
<p:ajax
update="@this foolbl bar barlbl"
process="@this"/>
</p:selectOneMenu>
<p:outputLabel id="barlbl" for="bar"
value="Bar" />
<p:selectOneMenu id="bar"
required="#{foobnd.valid and foobnd.value eq 'value1'}"
value="#{bean.bar}">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
value="#{bean.barValues}" />
<p:ajax update="@this barlbl" process="@this" />
</p:selectOneMenu>
It works fine, with the following exception:
- User selects "value 1" from foo. Result: Bean is updated with foo & bar becomes required;
- User selects some value from bar. Result: bean is updated with bar;
- User unselects the value in bar (selects "Select One"). Result: Validation fails because bar is required. Bean is not updated;
- User unselects value in foo (selects "Select One"). Result: Bean is updated with foo. Bar is updated with the previously submitted value of bean.bar ("value 1").
Obviously, this is working as it should per JSF. However, I am concerned that this will result in the user not noticing the problem, and accidentally submitting a value for bean.bar, when he did not intend to. It is sort of an edge case, but the user could select "Select One" in foo, and then subsequently select some value other than "value 1", resulting in a problem.
To avoid this, I could add bar to the process attribute of foo's ajax call, as follows:
<p:selectOneMenu id="foo" required="true"
value="#{bean.foo}" binding="#{foobnd}">
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems
value="#{bean.foovalues}" />
<p:ajax
update="@this foolbl bar barlbl"
process="@this bar"/>
</p:selectOneMenu>
This prevents the previously described problem, but it also has the unintended consequence of submitting the value for bar on the initial select of foo, and therefore highlighting bar as red for failing validation. I do not want this to happen. When foo is submitted, I only want the '*' to appear next to bar. I do not want it to be highlighted as validation failed.
I have experimented with listeners and customer validators to solve this problem, but so far nothing works quite right. resetValues also does not quite do what I want, as I don't like it to simply reselect the value the user just unselected.
I'm using PrimeFaces 6
What is the best way to accomplish this?