2015-08-17 30 views
13

Durante l'esecuzione di operazioni CRUD utilizzando JSF/PrimeFaces, è generalmente necessario un metodo comune che reimposta campi/proprietà bean gestiti che deve essere invocato fondamentalmente dopo che un'operazione di questo tipo è stata eseguita correttamente completato in modo che i campi nel backing bean vengano reimpostati sul loro valore iniziale (predefinito).Un potenziale metodo di richiamo dopo una richiesta POST (fondamentalmente Ajaxical)

codice immaginaria:

@Named 
@ViewScoped 
public class Bean extends LazyDataModel<Entity> implements Serializable { 

    @Inject 
    private Service service; // EJB. 

    // Holds a list of selected rows in a <p:dataTable>. 
    private List<Entity> selectedValues; // Getter & setter. 

    private String someField; // Getter & setter. 
    // Other fields depending upon the business requirement. 

    public Bean() {} 

    @PostConstruct 
    private void init() { 
     // Do something. 
    } 

    @Override 
    public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, Object> filters) { 
     setRowCount(service.rowCount()); 
     // Other complex logic as and when required. 
     return service.getList(first, pageSize, map, filters); // Returns a List<Entity>. 
    } 

    // Resets fields to their default value. 
    public void reset() { 
     someField = null; 
     selectedValues = null; 
     // Reset other fields to their default value. 
    } 

    // Add (insert submitted values to the database). 
    // This method is basically bound to an action(Listener) of <p:commandButton>. 
    public void submit() { 
     if (service.insert(someField)) { 
      // Add a FacesMessge to indicate a success. 
      reset(); // Calling reset. 
     } else { 
      // Add a FacesMessge to indicate a failure. 
     } 
    } 

    // Update the database using submitted values. 
    public void onRowEdit(RowEditEvent event) { 
     if (event.getObject() instanceof Entity) { 
      Entity entity = (Entity) event.getObject(); 
      Entity newEntity = service.update(entity); 

      if (newEntity != null) { 
       // Update the model. 
       // Other things like adding a FacesMessage to indicate a success. 
      } else { 
       // Add a FacesMessage to warn against the null entity returned by the service layer. 
      } 
     } else { 
      // Add a FacesMessage to indicate a failure. 
     } 

     reset(); // Finally reset the fields to their initial/default value. 
    } 

    // Similarly, performing the delete operation also requires to call the reset() method. 
} 

Procedimento submit() eseguito "inserto" è fondamentalmente associato JSF/primefaces componenti comando come <p/h:commandButton> o <p/h:commandLink>. Ad esempio.

<p:inputText value="#{bean.someField}"/> 

<p:commandButton value="Submit" 
       actionListener="#{bean.submit}" 
       oncomplete="if(args &amp;&amp; !args.validationFailed) {updateTable();}"/> 

<!-- Updating a p:dataTable in question after the above p:commandButton completes. --> 
<p:remoteCommand name="updateTable" update="dataTable" process="@this"/> 

I seguenti eventi AJAX associati a un <p:dataTable> richiedono anche per chiamare il metodo reset().

<p:ajax event="rowEdit" 
     onstart="..." 
     oncomplete="..." 
     update="..." 
     listener="#{bean.onRowEdit}"/> 

<p:ajax event="rowEditCancel" 
     onstart="..." 
     oncomplete="..." 
     update="..." 
     listener="#{bean.reset}"/> 

<p:ajax event="page" 
     onstart="..." 
     oncomplete="..." 
     update="..." 
     listener="#{bean.reset}"/> 

<p:ajax event="sort" 
     onstart="..." 
     oncomplete="..." 
     update="..." 
     listener="#{bean.reset}"/> 

<p:ajax event="filter" 
     onstart="..." 
     oncomplete="..." 
     update="..." 
     listener="#{bean.reset}"/> 

Come si può notare, il metodo reset() deve essere memorizzato con attenzione in quanto viene invocato da più punti. La via è alquanto difficile da mantenere.

Esiste un modo per richiamare un tale metodo comune automaticamente dopo ogni richiesta POST che esegue una delle operazioni CRUD ha completato correttamente il suo lavoro?

+0

Giusto per essere sicuri, si è consapevoli del fatto che è possibile specificare più valori in 'event' attributo? In questo modo: ''. Mi sembra che tutti gli altri attributi siano identici. – BalusC

+0

Sì, il resto degli attributi è identico (anche se 'reset()' deve essere richiamato manualmente dal bean di supporto durante l'inserimento, l'eliminazione. Suppongo di escludere anche quelle chiamate, se possibile). – Tiny

+0

Per sicurezza, è * dopo * ogni richiesta di post di un evento o * su * ogni richiesta di post di un evento? Sembra essere quest'ultimo ora, giusto? – Kukeltje

risposta

8

JSF non ha alcun tag per questo.

Idealmente, ti piacerebbe avere qualcosa come uno <f:event type="postInvokeAction" listener="#{bean.reset}"> direttamente collegato allo <p:dataTable>. Ma quell'evento non esiste in JSF 2.2. OmniFaces ne ha uno, ma è supportato solo su UIViewRoot, UIForm, UIInput e UICommand.

Il <f:phaseListener> si avvicina, ma viene collegato direttamente a UIViewRoot, anche se lo si inserisce all'interno di <p:dataTable>. E richiede un'intera implementazione PhaseListener.

Il <f:view afterPhase> sembra la soluzione migliore. Hai solo bisogno di un controllo aggiuntivo sull'ID di fase e sul componente di origine.

<p:dataTable binding="#{table}" ...> 
    <f:view afterPhase="#{bean.reset(table)}" /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    ... 
</p:dataTable> 
public void reset(UIData table) { 
    FacesContext context = FacesContext.getCurrentInstance(); 

    if (context.getCurrentPhaseId() != PhaseId.INVOKE_APPLICATION) { 
     return; 
    } 

    String source = context.getExternalContext().getRequestParameterMap().get("javax.faces.source"); 

    if (!table.getClientId(context).equals(source)) { 
     return; 
    } 

    // Reset logic here. 
    // ... 
} 

(binding potrebbe eventualmente essere sostituito da un hardcoded tabella client ID)


ho capito che questo è imbarazzante. Quindi, per il prossimo OmniFaces 2.2 ho altered l'esistente InvokeActionEventListener per supportare anche questo caso d'uso. Ora supporta l'aggiunta su qualsiasi UIComponent.

<p:dataTable ...> 
    <f:event type="postInvokeAction" listener="#{bean.reset}" /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    <p:ajax ... /> 
    ... 
</p:dataTable> 
public void reset() { 
    // ... 
} 
+0

Sebbene sia una buona soluzione, personalmente non penso che questo dovrebbe essere nel livello dell'interfaccia utente. Ma potrei non avere la conoscenza per capire perché dovrebbe essere meglio ... Quindi per favore mi illumini ... mai per i giovani^H^H^H^H^Tieni premuto per imparare – Kukeltje

+0

Puoi anche farlo senza tag in la vista, ma poi avresti bisogno di hardcode alcune cose specifiche della vista (ID e simili) nel bean/listener. È meno carino. I tag nella vista sono più dichiarativi e il controller/modello conosce meno la vista in quel modo. È sempre meglio :) – BalusC

+0

Non è quello che intendevo. Sono d'accordo che il controller/modello dovrebbe conoscere il minimo necessario (nessuno?) Sulla vista. Stavo piuttosto parlando di farlo in un "controller di base" Ogni sviluppatore che si rispetti che utilizza PrimeFaces LazyDataModel dovrebbe avere uno ... (se hai più entità ...). Cercherò di creare una "risposta" nel fine settimana per spiegare (o creare un blog) – Kukeltje