2012-05-23 9 views
5

En mi aplicación basada en JSF 2 tengo un formulario que incluye (entre otros componentes de UI) algunas casillas de verificación.Después del error de validación las solicitudes ajax subsiguientes obtienen valores de los Componentes de la interfaz de usuario y no de Beans

En las casillas de verificación, he registrado ajax solicitudes que se activan cuando se marcan. Las solicitudes ajax en realidad solo actualizarán el valor de otra casilla de verificación en el bean de respaldo. Como resultado, la otra casilla de verificación también se marcará (cuando se vuelva a procesar, ya que tomará el valor actualizado del bean de respaldo en la fase de respuesta de procesamiento).

Esto funciona bien hasta que se envíe el formulario completo y se produzcan errores de validación. Luego, las solicitudes ajax siguen funcionando y cambian el valor del bean de respaldo, pero en la fase de volver a generar la casilla actualizada el valor no se toma del bean de respaldo sino de un valor almacenado en caché de una clase ComponentStateHelper.

Por lo que yo entiendo, esto se usa para la nueva característica de JSF 2 para almacenar solo cambios parciales en el árbol de componentes.

Lo que no entiendo es: ¿Cómo se relaciona esto con la fase de validación? ¿Por qué hay un valor en caché en la clase StateHelper para mi casilla cuando la validación encontró errores?

Respuesta

4

Este es un problema conocido y se explica en profundidad en this answer. En pocas palabras, el problema se debe a que los componentes invalidados que van a ser renderizados por <f:ajax render> pero que no han sido ejecutados por <f:ajax execute> permanecen en un estado invalidado junto con el valor enviado original. Cuando JSF representa el componente de entrada, JSF primero comprobará si el valor presentado no es null y luego lo mostrará, de lo contrario mostrará el valor del modelo. Básicamente, debe restablecer el valor enviado de los componentes de entrada que se van a representar, pero que no han sido ejecutados por ajax.

Para lograr esto, se puede utilizar un ActionListener cuales básicamente realiza lo siguiente:

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(); 
} 

Esto ha sido reportado como JSF issue 1060 y una solución completa y reutilizable se ha implementado en la biblioteca OmniFaces como ResetInputAjaxActionListener (código fuente here y showcase demo here).

+0

Muchas gracias por su respuesta. Ya había incluido tu lib de omnifaces en mi proyecto de todos modos (para el 'FullAjaxExceptionHandlerFactory'). Así que fue fácil incluir 'ResetInputAjaxActionListener' en mi archivo' faces-config.xml'. Pero esto solo se llama en 'InvokeApplicationPhase' que mi solicitud ajax no afecta. Mi solicitud de ajax se desencadena con '' y allí con ''. Pero lo echaré un vistazo más de cerca. Simplemente probé tu sugerencia. – Jens

+0

No es golpeado? ¿Estás seguro? Es posible que deba reiniciar el servidor después de editar faces-config. – BalusC

+0

Lo reinicié y agregué el origen de las omnidades y establecí un punto de interrupción para ver si se golpeaba. Se atiende en solicitudes regulares pero no en la solicitud de ajax que se desencadena mediante la selección de la casilla de verificación. – Jens

Cuestiones relacionadas