Trying to understand immediate="true" skipping inputs when it shouldn't - jsf

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?

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:
Why was "immediate" attribute added to the EditableValueHolders?

Related

Cancel button jsf not resetting entity

I'm trying to implement a cancel button to clear the fields from my entity.
Though, when I'm setting the entity to null my fields still keep their value.
Code:
The EntityBB's cancel method (note that the debugger can reach the cancel method):
public void cancelAddStandardLetter() {
setEntity(null);
standardLetterInit();
}
this method really sets all the values from the entity back to null and the standardLetterInit method sets some default values that are needed (tried the same method without the standardLetterInit -> same result).
The xhtml page (other inputfields are left out):
<o:form includeRequestParams="true" id="addStandardLetterForm">
<h:inputTextvalue="#{entityBB.entity.fileName}" styleClass="rInput"/>
<h:commandButton value="Cancel" immediate="true"
styleClass="floatRight"
action="#{entityBB.cancelAddStandardLetter()}" />
</o:form>
After pressing the "cancel" button, the values being typed in the "fileName" field are still there. How can that be?
Make sure that the bean is view scoped and use a plain GET button.
<h:button value="Cancel" />
This basically refreshes the page. It'll recreate the view scoped bean instance. No need to submit the whole form. If the input values still appear, then it's either the browser cache or autocomplete/autofill which you in turn can control with respectively a servlet filter and autocomplete="off".

How does JSF process action listener?

I'm curious how JSF know that I click the button, with some action and it is even possible to call an action listener with a parameter. I can imagine the server notice the state and EL and call the methods.
Example 1:
<form>
<p:commandButton actionListener="{bean.do_something(bean.info)}" />
</form>
Example 2:
<form>
<h:datatable values=... var="myvar">
<h:column>
<p:commandButton actionListener="{bean.do_something(myvar.info)}" />
</h:column>
</h:datatable>
</form>
During the apply request values phase, the decode() method of all UIComponent instances in the component tree is executed. This is where the necessary HTTP request parameters are checked and collected. In case of UIInput components (<h:inputText> and friends), the submitted value is been obtained. In case of UICommand components (<h:commandButton> and friends), the ActionEvent is been queued.
In case of <p:commandButton> all the magic happens in CommandButtonRenderer#decode() whom a relevant part of the source code is extracted below (line numbers are from PrimeFaces 3.5):
34 public void decode(FacesContext context, UIComponent component) {
35 CommandButton button = (CommandButton) component;
36 if(button.isDisabled()) {
37 return;
38 }
39
40 String param = component.getClientId(context);
41 if(context.getExternalContext().getRequestParameterMap().containsKey(param)) {
42 component.queueEvent(new ActionEvent(component));
43 }
44 }
If you're familiar with basic HTML, you should already know that the name=value pair of every input element and only the pressed button of the enclosing form is been sent as request parameter to the server. The PrimeFaces command button generates basically the following HTML,
<button type="submit" name="formId:buttonId" ... />
where formId:buttonId is printed from UIComponent#getClientId(). It's exactly this value which is been used as HTTP request parameter name (the HTTP request parameter value is the button's label, but that's not further relevant here). If you're familiar with basic Servlets, which JSF runs on top of, then you should also already know that request parameters are available by HttpServletRequest#getParameter(), including the name=value pair of the buttons. This allows distinguishing the pressed button.
As you see in the above decode() method, exactly this UIComponent#getClientId() value is also been used in order to check if the HTTP request parameter map contains the parameter name. If so, then an ActionEvent will be queued which ultimately get invoked during invoke application phase.
As to the EL arguments, it's actually no rocket science. The whole EL expression is just executed during invoke application phase. It's not so that it's been executed during generating the HTML output of the form and then in some way passed as request parameter. No, it's just been executed during the actual invoke application phase.

Why was "immediate" attribute added to the EditableValueHolders?

Initially immediate flag was only intended for ActionSource interface. But later on it was added to the EditableValueHolder interface also. What was the reason for design decision ?
It's to be used to prioritize validation on several EditableValueHolder components in the same form.
Imagine a form containing input components with immediate="true" as well as input components without this attribute. The immediate inputs will be validated during apply request values phase (which is one phase earlier than usual). The non-immediate inputs will be validated during validations phase (which is the usual phase). If validation fails for at least one of the immediate inputs, then the non-immediate inputs won't be converted/validated at all and thus won't generate any conversion/validation error messages. This is particularly useful in forms with complex validation rules where it doesn't make sense to validate component Y when validation for (immediate) component X has failed anyway.
When used in combination with immediate="true" on a command button in the same form, this will cause all non-immediate inputs being completely skipped. A good real world example is a login form with 2 fields "username" and "password" with required="true" and 2 buttons: "login" and "password forgotten". You could put immediate="true" on the "username" field and the "password forgotten" button to skip the required="true" check on the password field.
In the dark JSF 1.x ages, the immediate="true" was also often (ab)used as a hack in combination with valueChangeListener and FacesContext#renderResponse(), more than often in cascading dropdown lists. Long story short, here's an old blog article on that. To the point, it enables developers to execute a backing bean method on change of a <h:selectOneMenu> without that all other inputs in the same form are been validated. But these days, with the ajax awesomeness, this hack is unnecessary. You can find a concretre example of this case at the bottom of our <h:selectOneMenu> wiki page.
These days, the immediate="true" is still often (ab)used in order to have a specific button which completely bypasses all other inputs, such as a logout button in a "God-form" antipattern (whereby everything is been thrown together in a huge <h:form>), or a cancel button which incorrectly submits the form. Such a button would break when you start to actually need the immediate="true" the right way on one of the inputs. You'd better put such a logout button in its own form, or to change it to process only itself (process="#this" in PrimeFaces). And you'd better change such a cancel button to just refresh the page synchronously by <h:button value="Cancel" />. This works fine if the form is tied to a request/view scoped bean and browser caching is disabled on dynamic pages.
See also:
Should immediate="true" never be used when dealing with an AJAXified JSF 2.0 component?
Trying to understand immediate="true" skipping inputs when it shouldn't

commandLink is not fired in a page with a param in its URI

When I call a method in a page with a param in its URI, the method is not invoked unless I pass the parameters of the uri again. For example if I have:
http://maywebsite/myapp/mypage.xhtml?mykey=myvalue
This method results in error (obviously because it renders the page again without params, but the method foo is never invoked):
<h:commandLink value="Do Action" actionListener="#{mybean.foo}"/>
So I added an ajax to only update the component, but the button is not getting fired:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:ajax render="somecomponent"/>
</h:commandLink>
When I passed the param values again, the button invokes the method just fine:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:param name="mykey" value="myvalue"/>
<f:ajax render="somecomponent"/>
</h:commandLink>
However, this button is included (ui:include) in many pages with different param keys and values. How can I invoke the method without passing the param values?
Im using glassfish 3.1.2, jsf 2.0
Apparently the bean is request scoped and the parameter plays a role in the way how the command link is rendered (e.g. by the rendered attribute on one of its parent components, or by a dynamic include of the template containing the command link).
All those conditions are namely re-evaluated during apply request values phase of the form submit. The developer has to make sure that all those conditions are exactly the same as when the form was presented to the enduser. So, when the bean is request scoped and the parameter is absent, then the command link appears as non-rendered in the component tree and this way its action won't be invoked.
Putting the bean in the view scope is the easiest way to fix this (unless you're using a dynamic <ui:include>, this is then more complicated, you'd need to turn off partial state saving for the particular view).
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5

Doubt on immediate attribute for command button

HI,
I have a doubt on setting the immediate attribute for the command button. I would like to know what will be the changes in the life cycle?
I have read that setting immediate attribute will call the action listener or action methods in the apply request values phase. My doubts is it only the difference of preponding the phase. Also it will execute the all the business logic in the action methods regardless of setting the immediate attribute.
Please clarify my doubts.
If immediate="true" is set in an UICommand component, then the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s) in the same UIForm. Use this to skip the entire processing of the form. E.g. "Cancel" or "Back" button.
If immediate="true" is set in both UIInput and UICommand components in the same UIForm, then the apply request values phase until with update model values phases will be skipped for any of the UIInput component(s) in the same form 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
Debug JSF lifecycle

Resources