{scrollbar}

Purpose

The immediate attribute can be used to achieve the following effects:

Overview

Before we can discuss immediate, we first need to review the JSF request processing lifecycle.

Many developers are under the impression that using the immediate flag on a component skips the "Process Validations" phase. It doesn't. What using immediate does is cause a component to be processed in the Apply Request Values phase.

UIInput Components

Using immediate means the component value will be validated during apply-request-values, ie before any non-immediate component values (which validate in process-validations). Any validation error in the set of input components that are marked immediate will cause processing to move to the render phase after the apply-request-values phase is complete, meaning that if any immediate component fails validation then errors associated with non-immediate components will not be shown. In addition, if the new value of an immediate input component is different from the existing value specified by the value attribute then a ValueChangeEvent is raised (as normal), but this event is processed at the end of the !ApplyRequestValues phase, NOT at the end of the ProcessValidations phase. In particular, this means that any ValueChangeListener associated with the component will execute before any immediate UICommand component's ActionListener (assuming the command component occurs later in the page).

Marking an input component as immediate does NOT affect the model update; any new data is still pushed into the model at the Update Model phase (ie after any immediate command components have executed). Note, however, that the !ValueChangeListener could be used to update the model directly.

UICommand Components

Using immediate causes the component ActionListener or action-method to be executed at the end of the apply-request-values phase, ie before any non-immediate value validation and before any backing bean updates (update-model phase).

If the action method is of a form that returns a navigation string, then:

For an action listener method that returns void, it is necessary to call

java facesContext.renderResponse();

if the normal flow is not desired.

The most significant issue when using an immediate input component is that new input data entered by the user is not usually available from the model as the update-model phase has not yet executed.

For non-immediate input components in the page, the only way an action method for an immediate command component can access user input data is by using component-binding or lookup-by-name to retrieve a specific UIComponent object then calling getSubmittedValue() to obtain the raw string provided by the user. This value has not been converted to its target type (using a user-specified or default Converter), nor has it been validated.

For immediate input components, the conversion and validation steps have been executed; using the corresponding UIComponent it is possible to get the converted value. Alternatively, if the component is "before" the UICommand component in the page, and has a !ValueChangeListener attached then that will have executed so any side-effects of that method (including direct update of a backing bean) can be relied upon to be available. Note, however, that if the component fails validation then no backing bean update will have been performed.

Warning: if the action method updates the model but does not perform navigation then any change to a backing bean value will be overwritten when the input component value goes through validation and update model.

Any immediate input components on the page that fail their validation will NOT stop immediate command components from executing; this is quite different from the behaviour for non-immediate input and command components.

See Also

Limitations

Using immediate for anything other than the trivial case of a cancel button is problematic.

Solution 1

First mark the relevant command component as immediate, then for each input component that the associated action method needs to implement:

xml <h:inputText value="#{pageBean.foo}" immediate="true" valueChangeListener="#{pageBean.setFoo}"/>

The referenced method looks like this:

java // normal property setter public void setFoo(String val) {...} // immediate input hack: update model at apply-request, not update-model public void setFoo(ValueChangeEvent ev) { setFoo((String) ev.getNewValue()); // prevent setter being called again during update-model phase ((UIInput) ev.getComponent()).setLocalValueSet(false); }

This effectively moves the update-model behaviour for the modified input component from the update-model phase into the apply-request-values phase. An immediate button can then access these values just like a non-immediate button accesses its inputs - except that the action listener method does need to manually check whether the validation failed for this component (in which case the ValueChangeListener never runs).

In the case where the input component's validation does fail, and the (immediate) action listener does not force navigation then the page will be redisplayed with only the immediate validation errors (not errors from any non-immediate components); this may be exactly what is wanted.

Solution 2

Have the action method invoked by the component access the raw components. However:

Solution 3

Don't make the command immediate at all; instead make the validation check whether it should run or not (see also the link below to the Optional Validation Framework).

For example, if the problem is a required field, then do something like this (untested code!):

xml <h:inputText required="#{!pageBean.cancelling}"/> java public boolean isCancelling() { // assumes cancelButton is a component binding FacesContext fc = FacesContext.getCurrentInstance(); Map reqParams = fc.getExternalContext().getRequestParameterMap(); return reqParams.containsKey(cancelButton.getClientId()); }

Solution 4

Use the tomahawk subform component. (The OptionalValidationFramework solution is no longer recommended or supported).

Other Relevant Information

Non-validated EditableValueHolder (UIInput) components render their submitted value, not the backing bean or local value.

Since only one group of components can be marked as immediate, you cannot have multiple kinds of immediate actions that depend on different component sets.

{scrollbar}