JSF

Just some random things that might make your JSF experience nicer

Tuesday, April 04, 2006

Cancel buttons an easy way

Lets start by saying what a typical cancel button would do?

So you need it to bypass validation check we can do that with the immediate attribute, but you might also want to update the variables e.g. repopulate your variables from a database etc.


And here lies the awkward position we are placed in.
Say your page failed validation you need to call FacesContext.getCurrentInstace().renderResponse() to bypass your validation phase. But JSF does not like to update the values held in your UIComponents. It seems calling renderResponse will leave you in the situation that your variables and values held in your components don’t match.

Now what they tell us to do is put immediate = true on all the components that will have their variables updated when the cancel button is clicked.

No thanks JSF !
That means the setters will be called before the validation phase? Yuk!

What a pain in design this is, say you want to update your entire page that means every component needs immediate = true? Seems a bit silly to me.




The solution I found :)


Place immediate = true on your cancel button this is a must. Need the button to execute before the validation phase.

But then execute a navigation rule lets call it “test”


FacesContext.getCurrentInstance().getApplication().getNavigationHandler().handleNavigation(FacesContext.getCurrentInstance(),null,"test");


Where test navigates from myPage back to myPage where the cancel button is


/myPage.jsp

test
/ myPage.jsp



This will force JSF to recreate the view and presto you have a cancel button

ValueChangeListeners what you need to know

Ok now I never quite figured this one out. The idea behind value change listeners should be simple. However EVERYONE gets confused because they don’t execute when expected.


Ok what you might of missed! Value change listeners are fired before the Setter methods are called.

So what?

Well this means any changes you make to variables from your value change method will be overwritten when the setters are called.


So I commonly hear just call FacesContext.getCurrentInstace.renderResponse()

so this should skip the phases meaning the setters are not called and go directly to the render response phase.

At first glance yes perfect it works.

What it doesn't do is update the VIEW ?
The getters are never called on your managed bean properties which means that the view is never updated with the values you change from you valueChangeListener.

How annoying :) so how to get around this.

1) You can force JSF to recreate the view.

Make a navigation rule to navigate back to the same page and call it in your value change method.

FacesContext.getCurrentInstance().getApplication().getNavigationHandler().handleNavigation(FacesContext.getCurrentInstance(),null,"test");

< navigation-rule >
< from-view-id > /myPage.jsp< /from-view-id >
< navigation-case >
< from-outcome > test< /from-outcome >
< to-view-id > / myPage.jsp< /to-view-id >
< /navigation-case >
< /navigation-rule >



2) Move the value change event to the update model phase.

This way your setters are called before your value change event something like

public void changeMethod(ValueChangeEvent event)
{
PhaseId phaseId = event.getPhaseId();
String oldValue = (String) event.getOldValue();
String newValue = (String) event.getNewValue();
if (phaseId.equals(PhaseId.ANY_PHASE))
{
event.setPhaseId(PhaseId.UPDATE_MODEL_VALUES);
event.queue();
}
else if (phaseId.equals(PhaseId.UPDATE_MODEL_VALUES))
{
// do you method here
}
}

3) Create your UICcomponents in your bean (use binding) and from your value change method call the .setMethod() on the UIComponents, then call the FacesContext.getCurrentInstance().renderResponse();
It appears the getters are called if you update the UI components directly.




I know these seems like hacks but for now I have not found any better solutions to what really seems like a flaw in the design

Hey all,
I am a developer in Australia been using JSF for around a year now.

The reason I started this blog was due to the fact i see the same questions over and over again in the JSF discussion boards. So instead of cut and copying my answers there I decided to just blog about the common problems I have found.