The “immediate” problem with JSF

So if you’ve developed with JSF before there’s a good chance you’ve run into problems using the “immediate” attribute. In case you’re unfamiliar with the immediate attribute here’s a quick description. Hopefully you’re already familiar with the JSF lifecycle which looks like this:

  1. Restore view
  2. Apply request values
  3. Process validation
  4. Update model
  5. Invoke application
  6. Render response

Typically you’ll have a form with a few fields. You may decided to add some validation to a field or make a field required. Now when you submit your form if any validations or conversions fail in the process validation phase of the JSF lifecycle you’ll skip straight to the render response phase. The same view will be rendered again and if you use the h:message or h:messages components the validation errors will be displayed. This is a great feature of JSF, but most forms also have a cancel button. However clicking the cancel button will still invoke the process validation and show you validation errors.

Enter the “immediate” attribute. On the cancel button you can specify an attribute called “immediate” and set its’ value to true. What this will do is tell JSF to skip to the invoke application phase right after the apply request values phase. Now we’re skipping over the validation and update phases and so we don’t need to worry about validation errors when clicking a cancel button.

A more complex scenario. This is a problem I faced the other day. I created a form that uses a drop down list as one of the fields. The user will then have an option to add items to the drop down list if the item they are looking for is not there. To accomplish this there is a command link that the user can click which will navigate away from the form. The user can then update the drop down list and return to the form. I’ve used the Tomahawk saveState component on the form page and the page that manages the drop down so that when I come back to the form, any data previously entered will still be there. Later on I added validation to the form and guess what? When I clicked that link to manage the drop down list I got validation errors instead of the page I expected to see. Then I thought to myself, “wait a minute, I just need to use the immediate attribute on that command link… problem solved”… or so I thought. Using the immediate attribute got rid of the validation problem but since I’m now skipping over the update model phase any data previously entered in the form is lost.

I did some searching around and found no easy solution to this problem so I came up with my own… and here it is.

I created an action listener on the bean for the command link which will find all UIInputs in the form and manually call their validator methods. If the data is valid then I call the update method as well. To my surprise this simple solution actually worked on the first try. For now it assumes that all the inputs are direct children of the form however it can be modified to handle all child components. So here it is.

public void saveRawFields(ActionEvent e) {
	UIComponent component = e.getComponent();

	while (!(component instanceof HtmlForm || component == null)) {
		component = component.getParent();
	}

	if (component == null) {
		throw new NullPointerException("component is null, "
				+ "maybe it's not inside a form?");
	}

	FacesContext context = FacesContext.getCurrentInstance();
	List children = component.getChildren();
	for (UIComponent c : children) {
		if (c instanceof UIInput) {
			UIInput input = (UIInput) c;

			input.processValidators(context);

			if (input.isValid()) {
				input.processUpdates(context);
			}
		}
	}
}

For some more info on the immediate attribute check out “How The Immediate Attribute Works”

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: