26

Just when I thought I had understood immediate... *sigh*

Consider the following JSF page:

<h:inputText value="#{testBean.text}" required="true" />
<h:commandButton actionListener="#{testBean.doFoo}" value="Do Foo" />
<h:commandButton immediate="true" actionListener="#{testBean.doBar}" value="Do Bar" /><br />
<h:outputText value="#{testBean.didSomething}" />

And this backing bean:

public class TestBean {
   private String didSomething = "Nothing done yet";
   // + getter

public void doFoo() {
    didSomething = "Did foo!";        
}

public void doBar() {
    didSomething = "Did bar!";        
}

From all I read about immediate I would expect the following:

  • When trying to do foo while not providing a value for the input field, the action is never executed because during processValidationsPhase an error occurs, resulting in the page to be re-rendered directly after this phase with an error message. The value of the didSomething remains unchanged. (This works as expected)

  • When trying to do bar while not providing a value for the input field, the action is executed during applyRequestValuesPhase because of the immediate attribute. The variable didSomething is changed. (This works as expected)

On what happens next, this description states:

"A null return value (as outcome of the action method) causes processing to continue as normal, ie non-immediate components are validated then update-model is executed (if no validation errors occurred). For an action listener method that returns void, it is necessary to call facesContext.renderResponse(); if the normal flow is not desired."

From this I had the idea that processing continues as normal (as my action method does neither return an outcome nor force renderResponse()), resulting in the same validation error. Only difference would be that it occurs after setting didSomething. However, this does not happen. Instead, it feels like the site still skips all remaining phases, with the input field not being touched. It re-renders without error message.

Can someone explain to me where my understanding of how this works is amiss?

BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
Louise
  • 1,411
  • 1
  • 17
  • 39
  • Which remaining phases? There's after the invoke action phase only one remaining phase: the render response phase. What exactly did you expect to happen besides rendering the response? Related: http://balusc.blogspot.com/2006/09/debug-jsf-lifecycle.html – BalusC Oct 18 '12 at 18:08
  • Well, the action for the immediate-button is not called during InvokeActions, but at the end of ApplyRequestValues, right? So if it does not disturb the normal flow, there should still be the ProcessValidations, UpdateModel and InvokeActions? – Louise Oct 18 '12 at 18:13
  • I see what you're getting at. I posted an answer. – BalusC Oct 18 '12 at 18:20

1 Answers1

45

With immediate="true" on the button, the action is indeed invoked during apply request values phase and all the remaining phases are skipped. That's also the sole point of this attribute: process (decode, validate, update and invoke) the component immediately during apply request values phase.

All inputs which do not have immediate="true" are ignored anyway. Only inputs which do have immediate="true" are also processed, but this happens also during apply request values phase. Why should the remaining phases be invoked if everything has already taken place in the apply request values phase?

In the Debug JSF lifecycle article you can find the following summary which should enlighten when to (not) use the immediate"true":

Okay, when should I use the immediate attribute?

If it isn't entirely clear yet, here's a summary, complete with real world use examples when they may be beneficial:

  • If set in UIInput(s) only, the process validations phase will be taken place in apply request values phase instead. Use this to prioritize validation for the UIInput component(s) in question. When validation/conversion fails for any of them, the non-immediate components won't be validated/converted.

  • If set in UICommand only, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s). Use this to skip the entire processing of the form. E.g. "Cancel" or "Back" button.

  • If set in both UIInput and UICommand components, the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s) which does not have this attribute set. Use this to skip the processing of the entire form expect for certain fields (with immediate). E.g. "Password forgotten" button in a login form with a required but non-immediate password field.

See also:

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • I updated the question with quotes from the linked source. Correct me if I'm wrong, but their description and yours give a different picture - with yours matching the actual behaviour. Is theirs somewhat faulty? – Louise Oct 19 '12 at 13:29
  • 1
    Apparently there was a bug in MyFaces which the article's author observed as correct behavior. – BalusC Oct 19 '12 at 13:34
  • Section 2.5.1 of the [jsf 2.2 spec](https://jcp.org/en/jsr/detail?id=344) is super readable and backs up BalusC's excellent explanation. – djeikyb Apr 09 '14 at 23:54
  • I think the example given in the last bullet, "*E.g. "Password forgotten" button in a login form with a required but non-immediate password field.*" very well matches the second bullet instead. When that button is pressed nothing in the form should be validated. (Mostly in real applications, there should be a link in place of a button to navigate directly to a password recovery page). – Tiny Sep 01 '15 at 15:59
  • 3
    @Tiny: the "Password forgotten" button (with `immediate="true"`) actually processes the username (as it has `immediate="true"`), but not the password (as it doesn't have `immediate="true"`). It basically reuses the login form as password forgotten form. With a GET link/button you'd need to press some button twice (one to go to the password forgotten form and another to submit it) and perhaps even re-enter the username if you don't pass it along as request param. – BalusC Sep 01 '15 at 16:01
  • It took time to comprehend but at last I managed to understand it thoroughly. Thank you. – Tiny Sep 01 '15 at 18:16