public class ResetInputAjaxActionListener extends DefaultPhaseListener implements ActionListener
How does it work? First, here are some JSF facts:
null
and the validated value is set as local value of the input component.
null
and
then display it, else if the local value is not null
and then display it, else it will display the
model value.
So, when the validation has failed for a particular form submit and you happen to need to update the values of input fields by a different ajax action or even a different ajax form (e.g. populating a field depending on a dropdown selection or the result of some modal dialog form, etc), then you basically need to reset the target input components in order to get JSF to display the model value which was edited during invoke action. Otherwise JSF will still display its local value as it was during the validation failure and keep them in an invalidated state.
The ResetInputAjaxActionListener
is designed to solve exactly this problem. There are basically three ways
to configure and use it:
Register it as <phase-listener>
in faces-config.xml
. It'll be applied
to every single ajax action throughout the webapp, on both UIInput
and
UICommand
components.
<lifecycle> <phase-listener>org.omnifaces.eventlistener.ResetInputAjaxActionListener</phase-listener> </lifecycle>
Or register it as <action-listener>
in faces-config.xml
. It'll
only be applied to ajax actions which are invoked by an UICommand
component such as
<h:commandButton>
and <h:commandLink>
.
<application> <action-listener>org.omnifaces.eventlistener.ResetInputAjaxActionListener</action-listener> </application>
Or register it as <f:actionListener>
on the invidivual UICommand
components where this action listener is absolutely necessary to solve the concrete problem. Note that it isn't
possible to register it on the individual UIInput
components using the standard JSF tags.
<h:commandButton value="Update" action="#{bean.updateOtherInputs}"> <f:ajax execute="currentInputs" render="otherInputs" /> <f:actionListener type="org.omnifaces.eventlistener.ResetInputAjaxActionListener" /> </h:commandButton>
This works with standard JSF, PrimeFaces and RichFaces actions. Only for RichFaces there's a reflection hack,
because its ExtendedPartialViewContextImpl
always returns an empty collection for render IDs.
See also RF issue 11112.
Design notice: being a phase listener was mandatory in order to be able to hook on every single ajax action as
standard JSF API does not (seem to?) offer any ways to register some kind of AjaxBehaviorListener
in an
application wide basis, let alone on a per <f:ajax>
tag basis, so that it also get applied to
ajax actions in UIInput
components. There are ways with help of SystemEventListener
, but it
ended up to be too clumsy.
Constructor and Description |
---|
ResetInputAjaxActionListener()
Construct a new reset input ajax action listener.
|
ResetInputAjaxActionListener(ActionListener wrapped)
Construct a new reset input ajax action listener around the given wrapped action listener.
|
Modifier and Type | Method and Description |
---|---|
void |
beforePhase(PhaseEvent event)
Delegate to the
processAction(ActionEvent) method when this action listener is been registered as a
phase listener so that it get applied on all ajax requests. |
void |
processAction(ActionEvent event)
Handle the reset input action as follows, only and only if the current request is an ajax request and the
PartialViewContext.getRenderIds() does not return an empty collection nor is the same as
PartialViewContext.getExecuteIds() : find all EditableValueHolder components based on
PartialViewContext.getRenderIds() and if the component is not covered by
PartialViewContext.getExecuteIds() , then invoke EditableValueHolder.resetValue() on the
component. |
afterPhase, getPhaseId
public ResetInputAjaxActionListener()
<f:actionListener>
or when registering as <phase-listener>
in
faces-config.xml
.public ResetInputAjaxActionListener(ActionListener wrapped)
<action-listener>
in faces-config.xml
.wrapped
- The wrapped action listener.public void beforePhase(PhaseEvent event)
processAction(ActionEvent)
method when this action listener is been registered as a
phase listener so that it get applied on all ajax requests.beforePhase
in interface PhaseListener
beforePhase
in class DefaultPhaseListener
processAction(ActionEvent)
public void processAction(ActionEvent event) throws AbortProcessingException
PartialViewContext.getRenderIds()
does not return an empty collection nor is the same as
PartialViewContext.getExecuteIds()
: find all EditableValueHolder
components based on
PartialViewContext.getRenderIds()
and if the component is not covered by
PartialViewContext.getExecuteIds()
, then invoke EditableValueHolder.resetValue()
on the
component.processAction
in interface ActionListener
IllegalArgumentException
- When one of the client IDs resolved to a null
component. This
would however indicate a bug in the concrete PartialViewContext
implementation which is been used.AbortProcessingException