After a validation error, subsequent ajax requests receive values ​​from user interface components, not Beans

In my JSF 2-based application, I have a form that includes (among other interface components) some checkboxes.

On the flags, I registered ajax requests that fire when they are checked. Ajax requests will actually just update the value of another flag in the bean database. As a result, another flag will also be checked (when it is re-displayed), since it will accept the updated value from the backup bean in the rendering response phase).

This works fine until the entire form is submitted and validation errors are made. Then the ajax requests still work and change the value based on the bean, but in the phase of re-rendering the updated flag, the value for it is not taken from the backup bean, but from the cached value, which is taken from the ComponentStateHelper class.

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

I do not understand: how is this connected with the verification phase? Why StateHelper class have a cached value for my flag when it encounters validation errors?

+6
source share
1 answer

This is a known issue and is explained in detail in this answer . In a nutshell, the problem arises due to the fact that invalid components that should be displayed <f:ajax render> , but were not executed <f:ajax execute> , remain in the invalid state along with the original passed value. When the JSF displays the input component, the JSF first checks to see if the represented value is not null , and then displays it, otherwise it displays the model value. You basically need to reset the represented value of the input components that need to be rendered, but which are not 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 was reported as JSF issue 1060 , and a complete and reusable solution was implemented in the OmniFaces library ResetInputAjaxActionListener (source code here and demo here ).

+4
source

Source: https://habr.com/ru/post/916471/


All Articles