Problems related with ValueChangeListeners in JSF

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

0 comments: