31 Mar 2012

Update model in the ValueChangeListener

After reading of the Understanding the JSF Immediate Attribute post, my friend asked me whether there is any sense to use the Immediate attribute for inputTexts. The answer is Yes, off course. In general we set the Immediate to true when we need to validate the component and execute its value change events before the common validation process, before the Process Validation phase. We move up the validation and the value change events processing to the Apply Request Values phase. In other words, we split our components into two parts: front-line or Immediate inputs that are validated first at the Apply Request Values and all others that are validated later at the usual Process Validation phase. In this post I'm going to show one of use-cases when the Immediate attribute for inputTexts could be useful.
Let's say we have two inputTexts:

        <af:inputText label="Label Value" id="it1"
                      value="#{backing_Main.labelValue}" autoSubmit="true"
                      />

        <af:inputText label="#{backing_Main.labelValue}" id="it2"
                      partialTriggers="it1"/>

The first one stores its value in some backing bean property (in the model), and the second input reads this property to render its label. The first input is autosubmit and it partially triggers the second input, so when we change value of the first input and press Tab, label of the second one is going to be changed immediately. At this point both inputs are not Immediate and everything works fine:

Let's change the required attribute of the second input to true and we get validation error:

To resolve this issue let's set Immediate of the first input to true and add a valueChangeListener. In the valueChangeListener we need to manually update model for the first input because we are going to skip all the subsequent phases (including Update Model phase) except Render Response:

   public void labelListener(ValueChangeEvent valueChangeEvent)
  { UIComponent c = valueChangeEvent.getComponent();
    
    //This step actually invokes Update Model phase for this 
    //component
    c.processUpdates(FacesContext.getCurrentInstance());
    
    //Jump to the Render Response phase in order to avoid 
    //the validation
    FacesContext.getCurrentInstance().renderResponse();
  }

And it works fine again:



That's it!

11 comments:

  1. This and your previous post "Understanding the JSF Immediate Attribute" was VERY helpfully!
    Now I think I got it. Thank you!!

    ReplyDelete
  2. When the first input text is immediate and required, AND you have the immediate toolbar button, what happens with first input text when you click on button ? Are you getting error "A value is requred" ?

    ReplyDelete
  3. Yes, in this case you're going to get an exception. And you can read how to avoid it here:
    http://adfpractice-fedor.blogspot.com/2012/04/how-to-avoid-validation-of-immediate.html

    ReplyDelete
  4. Thanks, I will take a look.
    In the mean time, I have the following situation, maybe you can help ?


    In my (autoSubmit) af:inputText, I have valueChangeListener, in which (under some circumstances) I call

    FacesContext.getCurrentInstance().renderResponse();

    In this way, in fact I want to skip my actionListener attached on the command toolbar button residing on the same form. So, when the user changes the inputText value, and (while staying on the input text) click on the button, it triggers the valueChangeListener which calls renderResponse(), but after that, the actionListener are also performed.
    This, however, does not occur if the autoSubmit for the inputText is false, namely, lifecycle goes directly to the render response phase, without executing action listener.

    So, how to skip invoke action phase when autoSubmit=true ?
    Thanks,...

    ReplyDelete
    Replies
    1. When you have an autosubmit inputText, and press a button, you actually have 2 requests. The first one submits data of the inputText (because it's lost the focus and it is an autosubmit one), the second one processes button click event. So, your ValueChangeListener stops only the first request. In case of autosubmit=false, you have one request only, and you stop its processing in the ValueChangeListener. The question is – why do you need to skip actionListener of the button?

      Delete
  5. Hi Eugene,

    A piece of your code helped to fix something I have been trying since 10 hours.
    Thanks a lot. Much appreciated!

    Hitesh

    ReplyDelete
  6. This post was really helpful.Since my partial trigger on the Lov was not working and just giving error that value is required.thanks a lot Eugene

    ReplyDelete
  7. Hi Eugene,

    The post was really useful.

    But now i have a case where I have Cancel button with immediate true.
    The"first input" also has required=true .

    if value in "first input" is 1 then "second input" is enabled. your solution worked perfectly for the case.

    but when i try to click on cancel it give me required validation for "first input".

    Any suggestion for this case?

    Ravi

    ReplyDelete
    Replies
    1. Hi!
      Try to use this technique:
      http://adfpractice-fedor.blogspot.com/2012/04/how-to-avoid-validation-of-immediate.html

      Delete

Post Comment