1
votes

I want to reset JSF inputs to their original managed bean values after validation failed.

I have two forms inside the same page - the first form has a commandLink to initialize the second form. The second form is rendered as a dialog whose visibility is toggled through jQuery - for the purpose of this exercise, though, I can illustrate just with two forms on the same page. Also, while I'm using PrimeFaces 2.2.x in my app, the same behaviors appear with regular h:commandLink as well.

The issue I'm having is:

  1. click link in first form to initialize second form
  2. submit invalid values in second form
  3. click link in first form again to initialize second form - invalid values still there and/or UIInput state is still invalid.

For example - take the following form

<h:form id="pageForm">
    <h:commandLink actionListener="#{testBean.initialize}">Initialize, no execute
        <f:ajax render=":dialogForm"/>
    </h:commandLink>
    <br/>
    <h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=@this
        <f:ajax execute="@this" render=":dialogForm"/>
    </h:commandLink>

</h:form>

<h:form id="dialogForm">
    <h:messages/>
    String property - Valid: <h:outputText value="#{property.valid}"/>
    <br/>
    <h:inputText id="property" binding="#{property}" value="#{testBean.property}">
    <f:validateLength minimum="3"/>                         
    </h:inputText>
    <br />
    Int property - Valid: <h:outputText value="#{intValue.valid}"/>
    <h:inputText id="intValue" binding="#{intValue}" value="#{testBean.intValue}">
        <f:validateLongRange maximum="50" />                            
    </h:inputText>
    <br/>

    <h:commandLink actionListener="#{testBean.submit}">
        Submit
        <f:ajax render="@form" execute="@form"/>
    </h:commandLink>

    <h:commandLink actionListener="#{testBean.initialize}">Initialize, execute=@this
        <f:ajax execute="@this" render="@form"/>
    </h:commandLink>

</h:form>

Bean class:

@ManagedBean
@ViewScoped
public class TestBean {
  private String property = "init";
  private Integer intValue = 33;
  // plus getters/setters

  public void submit() { ... }
  public void initialize() {
   intValue = 33;
   property = "init";   
  }

}

Behavior #1

  1. click either "Initialize" link on the pageForm
  2. inputs get initialized to "init", "33"
  3. now submit something invalid for both fields like "aa", "99"
  4. now click any of the "initialize" links again (they all seem to behave the same - makes no difference whether it's in the same form or different, or whether I have specified execute="@this" or not.)

Result => UIInput.isValid() = false, both values reset though ("init", "33").

Expected => valid = true (or is this not reasonable to expect?)

Behavior #2

  1. click either "Initialize" link on the pageForm
  2. inputs get initialized to "init", "33"
  3. now submit something invalid for the text field but valid for the int field ("aa", "44")
  4. now click any of the "initialize" links again

Result => "init", valid=false; 44, valid=true

Expected => "init", valid=true; 33, valid=true

I have also looked at:

JSF 2 - Bean Validation: validation failed -> empty values are replaced with last valid values from managed bean

and

How can I populate a text field using PrimeFaces AJAX after validation errors occur?

The suggestion to explicitly reset the state of UIInputs with resetValue does work, but I'm not happy with it.

Now, I sort of understand why the isValid is not resetting - my understanding of the JSF lifecycle is that once a value is submitted to a component, isValid is not reset until the component is successfully submitted and validated and the Update Model Values phase sets the bean value. So there may be no way around explicitly resetting the valid state in this case, since I want to use #{foo.valid} for conditional CSS styling.

What I don't understand, though, is why the components that successfully validated are not re-initializing from the bean. Perhaps my understanding of the JSF lifecycle is slightly off?

I understand the rules layed out in the answer to How can I populate a text field using PrimeFaces AJAX after validation errors occur? as they pertain to an individual component but not to the form as a whole - i.e., what happens if a component succeeds validation but the validation overall fails?

1
What PrimeFaces version are you using? On my PF 2.2.1 testbed there's no .open() function on the dialog widget at all.BalusC
My dialogs are just straight jQuery, not using p:dialog.wrschneider
Oh? You should have mentioned that.. How about when you fix update="dialog" to update="dialogForm" as in my answer?BalusC
I finally got a chance to work on some better examples to clarify. It's not a dialog issue per se - it's about trying to initialize a form from a commandLink (same or different form) action listener.wrschneider

1 Answers

1
votes

In fact, there may turn out to be no better way than explicitly calling resetValue on components. In my case, all of the dialogs are in the same big JSF view tree with the underlying page that opens them. So from JSF's perspective, the same view component state including invalid input values should be preserved until we navigate away from the view, as it has no visibility into how we're toggling display attributes client-side.

The only other thing that might work is if the components that make up the dialog are actually not rendered in the JSF view tree unless they're visible. In my case, they're always rendered, using CSS to toggle visibility.