6

In my JSF 2 based application I have a form that includes (amongst other UI components) some checkboxes.

On the checkboxes I have registered ajax requests that fire when they are checked. The ajax requests will actually just update the value of another checkbox in the backing bean. As a result the other checkbox will also be checked (when it gets re-rendered - as it will take the updated value from the backing bean in the render response phase).

This works fine until the whole form gets submitted and validation errors occur. Then the ajax requests still work and change the value on the backing bean but in the phase of re-rendering the updated checkbox the value for it is not taken from the backing bean but from a cached value that is taken from a ComponentStateHelper class.

As far as I understand this is used for the new feature of JSF 2 to only store partial changes to the component tree.

What I do not understand is: How is this related to the validation phase? Why is there a cached value in the StateHelperclass for my checkbox when the validation found errors?

Jens
  • 5,615
  • 1
  • 45
  • 71

1 Answers1

4

This is a known problem and explained in depth in this answer. In a nutshell, the problem is caused because the invalidated components which are to be rendered by <f:ajax render> but are not been executed by <f:ajax execute> remains in an invalidated state along with the original submitted value. When JSF renders the input component, JSF will first check if the submitted value is not null and then display it, else it will display the model value. You basically need to reset the submitted value of input components which are to be rendered, but which are not been executed by ajax.

To achieve this, you can use an ActionListener which basically does the following:

UIViewRoot viewRoot = context.getViewRoot();
PartialViewContext partialViewContext = facesContext.getPartialViewContext();
Set<EditableValueHolder> inputs = new HashSet<EditableValueHolder>();

// First find all to be rendered inputs and add them to the set.
findAndAddEditableValueHolders(partialViewContext.getRenderIds(), inputs);

// Then find all executed inputs and remove them from the set.
findAndRemoveEditableValueHolders(partialViewContext.getExecuteIds(), inputs);

// The set now contains inputs which are to be rendered, but which are not been executed. Reset them.
for (EditableValueHolder input : inputs) {
    input.resetValue();
}

This has been reported as JSF issue 1060 and a complete and reuseable solution has been implemented in the OmniFaces library as ResetInputAjaxActionListener (source code here and showcase demo here).

Community
  • 1
  • 1
BalusC
  • 992,635
  • 352
  • 3,478
  • 3,452
  • Thanks a lot for your answer. I had already included your omnifaces lib in my project anyways (for the `FullAjaxExceptionHandlerFactory`). So it was easy to just include the `ResetInputAjaxActionListener` in my `faces-config.xml` file. But this is only called in the `InvokeApplicationPhase` which is not hit by my ajax request. My ajax request is triggered by a `` and in there by ``. But I will have a closer look at this. I just quickly tried your suggestion. – Jens May 24 '12 at 11:25
  • It's not hit? Are you sure? You may need to restart the server after editing faces-config. – BalusC May 24 '12 at 12:46
  • I did restart it and I added the source of omnifaces and set a breakpoint to see if it gets hit at all. It does get hit on regular requests but not on the ajax request that gets triggered by the selection of the checkbox. – Jens May 24 '12 at 20:24
  • I just added the code to reset the values on the input components right at the place where the first checkbox sets the value of the second checkbox (in my backing bean). Like this: `ResetInputAjaxActionListener resetter = new ResetInputAjaxActionListener(); resetter.processAction(null);` Then everything works fine. So I guess I just have to find a better place to trigger the reset. (still wondering though why the `ActionListener` is not triggered by the axaj request that fires when the checkbox is checked.) – Jens May 25 '12 at 09:05
  • What JSF impl/version are you using? – BalusC May 25 '12 at 11:19
  • I am using the provided JSF version of JBoss 7.1.0 final which should be 2.1.5 (if I'm not mistaken). – Jens May 25 '12 at 12:44