2011-01-31 23 views
11

Cómo omitir la validación JSR-303 Bean con JSF, cuando se hace clic en un botón?JSF 2.0: ¿Cómo saltarse la validación del bean JSR-303?

Un poco largo pregunta para explicar algunos enfoques ... Considere una lista en un formulario:

<h:form id="form"> 
    <h:commandButton value="Add row"> 
     <f:ajax execute="foo" listener="#{bean.add()}" render="foo" /> 
    </h:commandButton> 
    <h:dataTable id="foo" var="foo" value="#{bean.foos}"> 
     <h:column> 
      Name: <h:inputText id="field" value="#{foo.name}" required="true" /> 
      <h:messages for="field" /> 
     </h:column> 
     <h:column> 
      <h:commandButton value="Remove"> 
       <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" /> 
      </h:commandButton> 
     </h:column> 
    </h:dataTable> 
</h:form> 

Cuando el usuario hace clic añadir o eliminar fila, la acción debe ejecutarse sin validación. El problema es que JSF vuelve a renderizar toda la lista e intenta validarla. Si hay cambios de borrador que no se validan, se producen errores de validación y nunca se llama al método de escucha (ya que la validación fallida evita eso). Sin embargo, agregar immediate="true" en f: ajax permite que el método se ejecute a pesar de los errores de validación. Sin embargo, los errores de validación todavía ocurren y se muestran aquí.

veo dos opciones:

1) uso inmediato = "true" y no muestran errores de validación

Para no validador botones, ajuste inmediato = "true" y por h: mensajes hacen:

<h:messages rendered="#{param['SHOW_VALIDATION']}" /> 

Entonces conjunto protegido botón (que realmente debe tratar de guardar el formulario) para enviar ese parámetro:

<h:commandButton> 
    <f:param name="SHOW_VALIDATION" value="true" /> 
</h:commandButton> 

Esto provoca la validación, pero los mensajes simplemente no se muestran excepto cuando el parámetro SHOW_VALIDATION está presente.

2) Declarar la validación en facelets condicionalmente:

<h:inputText> 
    <f:validateRequired disabled="#{!param['VALIDATE']}" /> 
</h:inputText> 

Y el botón Save-:

<h:commandButton> 
    <f:param name="VALIDATE" value="true" /> 
</h:commandButton> 

Esto provoca campos para validar sólo cuando el parámetro VALIDATE está presente (= cuando el botón Guardar ha sido presionado).

Pero estos parecen una especie de pirateo. ¿Cómo puedo simplemente usar JSR-303 Bean Validation pero omitirlo cuando se declare?

+0

Bueno, no he probado ninguna otra solución de validación que JSR-303 y facelets con JSF. Creo que este problema está relacionado con JSF y no con JSF-303; es como si se olvidaron de admitir "de forma nativa" la validación de omisión en JSF. Parece que hay mucha confusión en torno a esto ... –

Respuesta

9

Configure sus controladores de eventos como immediate=true y llame al FacesContext.renderResponse() antes de salir de ellos.

ACTUALIZACIÓN:

Las modificaciones en el ejemplo de formulario:

<h:form id="form"> 
    <h:commandButton value="Add row"> 
     <!-- Added immediate="true" to call bean.add() before validation phase --> 
     <f:ajax execute="foo" listener="#{bean.add()}" render="foo" immediate="true"/> 
    </h:commandButton> 
    <h:dataTable id="foo" var="foo" value="#{bean.foos}"> 
     <h:column> 
      Name: <h:inputText id="field" value="#{foo.name}" required="true" /> 
      <h:messages for="field" /> 
     </h:column> 
     <h:column> 
      <h:commandButton value="Remove"> 
       <!-- Added immediate="true" to call bean.remove() before validation phase --> 
       <f:ajax execute=":form:foo" listener="#{bean.remove(foo)}" render=":form:foo" immediate="true"/> 
      </h:commandButton> 
     </h:column> 
    </h:dataTable> 
</h:form> 

Las modificaciones en el código de frijol:

... 
public void add() { 
    // Your add() code 
    ... 
    // Added FacesContext.renderResponse() call to skip to render response phase 
    FacesContext.getCurrentInstance().renderResponse(); 
} 
... 
public void remove() { 
    // Your remove() code 
    ... 
    // Added FacesContext.renderResponse() call to skip to render response phase 
    FacesContext.getCurrentInstance().renderResponse(); 
} 
... 
+0

¿Cómo se hace eso en la práctica? ¿Puede dar un ejemplo? –

+0

Para dejar en claro: Hacer esto hace que JSF omita las fases número 3-5 (validaciones del proceso, modelo de actualización, solicitud de invocación) y pasa directamente a la fase 6 (respuesta de procesamiento). Esto está bien, ya que el resultado es similar al de las validaciones fallidas en la fase 3 y JSF saltaría a la fase 6. Corrígeme si está mal. El siguiente paso de esto sería generalizar/componer esto para que no se necesite llamar a 'FacesContext.getCurrentInstance(). RenderResponse()'. Escogiendo como la respuesta aceptada, ¡gracias por la buena solución! :) –

+1

He intentado lo anterior y, en general, funciona bien. Mi caso es el siguiente: utilizo un botón de comando para agregar dinámicamente un número de cuadros de texto a la página. Si uso 'immediate =" false "', la validación de la página evitará la actualización y no se mostrará también. Si utilizo valores 'inmediatos =" verdaderos '', y modifico algunos valores de entrada '' antes de hacer la solicitud AJAX, las modificaciones no serán enviadas. ¿Alguna idea de cómo puedo lograr tanto la lectura de los datos de entrada cambiados en la devolución de llamada y no desencadenar la validación al mismo tiempo? Gracias de antemano –

8

puede desactivar la validación de habas con la etiqueta f: validateBean que tiene un atributo deshabilitado.

Ejemplo:

<h:inputText value="#{bean.name}"> 
    <f:validateBean disabled="#{anotherBean.flag}"/> 
</h:inputText> 
+0

Esta es una buena información también. Sin embargo, todavía es un poco engorroso establecer esto para cada campo en la forma ... –

+2

Puede envolver varios componentes de entrada con 'f: validateBean' también, como se muestra aquí: http://stackoverflow.com/a/17503608/ 1725096 –

-1

Situación: En el código de la página hay una gran forma con muchos campos de entrada. Hay varios botones cada uno apuntando a una acción separada en el bean separado.

Una solución que funcionó para mí ...

  1. En el código de la página: añadir immediate="true" al botón y proporcionar un ID para los campos de entrada que desea utilizar en el grano.
<p:inputText id="someHtmlInputId" 
       maxlength="30" 
       value="#{beanName.attr}" /> 


<p:commandButton id="someHtmlButtonId" 
        actionListener="#{beanName.doStuff}" 
        value="Button Label" 
        ajax="false" 
        immediate="true"/> 
  1. En el método de frijol doStuff obtener los parametes por la Couse fragmento nombre antes del nombre de entrada JSF puso algunos otros identificadores y el nombre del parámetro resultante puede tener este aspecto: someFormId: j_idt54 : someHtmlInputId
Map<String, String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap(); 
if (params != null) { 
    for (String k: params.keySet()) 
     if (k.indexOf("someHtmlInputId") != -1) 
      params.get(k); // This is Your input parameter value waiting to be processed ;) 
} 
Cuestiones relacionadas