2011-01-31 19 views
11

Come saltare la convalida del bean JSR-303 con JSF, quando si fa clic su un pulsante?JSF 2.0: come saltare la convalida del bean JSR-303?

Una lunga questione po 'di spiegare alcuni approcci ... Si consideri una lista in una forma:

<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> 

Quando l'utente fa clic aggiungere o rimuovere fila, l'azione deve essere avviata senza convalida. Il problema è che JSF ridisegna l'intera lista e prova a convalidarla. Se ci sono bozze di modifiche che non si verificano, si verificano errori di convalida e il metodo listener non viene mai chiamato (poiché la convalida non riuscita lo impedisce). Tuttavia, aggiungendo immediate="true" in f: ajax consente l'esecuzione del metodo nonostante gli errori di convalida. Tuttavia, gli errori di convalida si verificano ancora e sono mostrati qui.

vedo due opzioni:

1) l'uso immediato = "true" e non mostrano errori di validazione

Per non-validante pulsanti, impostare immediata = "true" e per h: i messaggi fanno:

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

Poi il set salva-tasto (che dovrebbe in realtà cercare di salvare il modulo) per inviare quel parametro:

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

Ciò provoca la convalida, ma i messaggi semplicemente non vengono visualizzati tranne quando è presente il parametro SHOW_VALIDATION.

2) dichiarare la convalida in facelets condizionalmente:

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

e salva-pulsante:

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

Questo fa sì che i campi di convalidare solo quando il parametro VALIDATE è presente (= quando il pulsante Save è stato premuto).

Ma questi sembrano una specie di hack. Come posso semplicemente usare JSR-303 Bean Validation ma saltarlo quando dichiarato?

+0

Bene, non ho provato altre soluzioni di convalida di JSR-303 e facelets con JSF. Penso che questo problema sia relativo a JSF e non alla colpa di JSF-303 - è come se si dimenticassero di supportare "nativamente" la salta della convalida in JSF. Sembra che ci sia molta confusione intorno a questo ... –

risposta

9

Impostare i gestori di eventi come immediate=true e chiamare FacesContext.renderResponse() prima di uscire.

UPDATE:

modifiche nel modulo esempio:

<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> 

modifiche nel codice di fagioli:

... 
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

Come lo fai in pratica? Puoi fare un esempio? –

+0

Per rendere più chiaro: facendo ciò, JSF salta le fasi numero 3-5 (convalida del processo, aggiorna il modello, richiama l'applicazione) e passa direttamente alla fase 6 (risposta di rendering). Questo è ok, poiché il risultato è come se le convalide fallissero nella fase 3 e JSF salta alla fase 6. Correggimi se è sbagliato. Il prossimo passo da questo sarebbe generalizzare/componentizzare così chiamando 'FacesContext.getCurrentInstance(). RenderResponse()' non sarebbe necessario. Scegliere come risposta accettata, grazie per la bella soluzione! :) –

+1

Ho provato quanto sopra e in generale funziona bene. Il mio caso è il seguente: utilizzo un pulsante di comando per aggiungere dinamicamente un numero di caselle di testo alla pagina. Se utilizzo 'immediate =" false "', la convalida della pagina impedirà l'aggiornamento e non verrà visualizzato. Se uso 'immediate =" true "', e modifico alcuni valori di input prima di fare la richiesta AJAX, le modifiche non saranno inviate. Qualche idea: come posso ottenere sia la lettura dei dati di input modificati nel callback, che non attivare la convalida nello stesso momento? Grazie in anticipo –

8

è possibile disattivare la convalida di fagioli con il tag f: validateBean che ha un attributo disabilitato.

Esempio:

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

Questa è una buona informazione pure. Tuttavia, è ancora un po 'ingombrante impostare questo per ogni campo nel modulo ... –

+2

Puoi racchiudere più componenti di input con 'f: validateBean', come mostrato qui: http://stackoverflow.com/a/17503608/ 1725096 –

-1

Situazione: Nel codice della pagina c'è una grande forma con molti campi di input. Ci sono diversi pulsanti ciascuno che punta a separare l'azione nel bean separato.

Una soluzione che ha funzionato per me ...

  1. nel codice della pagina: aggiungi immediate="true" al pulsante e fornire un ID per i campi di input che si desidera utilizzare nel chicco.
<p:inputText id="someHtmlInputId" 
       maxlength="30" 
       value="#{beanName.attr}" /> 


<p:commandButton id="someHtmlButtonId" 
        actionListener="#{beanName.doStuff}" 
        value="Button Label" 
        ajax="false" 
        immediate="true"/> 
  1. Nel metodo di fagioli doStuff ottenere i parametes da parte del couse nome del frammento prima del nome di input JSF mettere alcuni altri identificatori e il nome del parametro risultante può apparire come segue: 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 ;) 
} 
Problemi correlati