2015-08-17 2 views
13

Bei der Ausführung von CRUD-Vorgängen mit JSF/PrimeFaces wird im Allgemeinen eine allgemeine Methode zum Zurücksetzen von verwalteten Bean-Feldern/Eigenschaften benötigt, die im Grunde nach einer solchen Operation aufgerufen werden soll abgeschlossen, so dass die Felder in der Backing-Bean auf ihren ursprünglichen (Standard) Wert zurückgesetzt werden.Eine mögliche Methode, die aufgerufen wird, nachdem eine POST-Anforderung (im Grunde genommen Ajax)

Imaginär-Code:

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

Die submit() Verfahren durchzuführen "Einfügen" ist im Grunde genommen mit JSF/PrimeFaces Befehlskomponenten wie <p/h:commandButton> oder <p/h:commandLink> verbunden. Sowie.

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

Die folgenden AJAX Veranstaltungen mit <p:dataTable> auch im Zusammenhang erfordern die reset() Methode aufzurufen.

<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}"/> 

Wie man sehen kann, die reset() Verfahren sorgfältig werden muss auswendig gelernt, wie es von mehreren Stellen aufgerufen wird. Der Weg ist etwas schwierig zu pflegen.

Gibt es eine Möglichkeit, eine solche allgemeine Methode automatisch aufzurufen, nachdem jede POST-Anforderung, die eine der CRUD-Operationen ausführt, erfolgreich abgeschlossen wurde?

+0

Nur um sicherzugehen, sind Sie sich bewusst, dass Sie mehrere Werte in 'event' Attribut angeben? Wie folgt: ''. Mir scheint, dass auch alle anderen Attribute identisch sind. – BalusC

+0

Ja, der Rest der Attribute ist identisch (obwohl 'reset()' manuell vom Backend-Bean aufgerufen werden muss, wenn eingefügt, gelöscht wird. Ich nehme an, diese Aufrufe auch auszuschließen, wenn möglich). – Tiny

+0

Nur um sicher zu gehen, ist es * nach * jeder Postanfrage einer Veranstaltung oder * auf * jeder Postanfrage einer Veranstaltung? Es scheint jetzt letzteres zu sein, oder? – Kukeltje

Antwort

8

JSF hat keine Markierung dafür.

Idealerweise möchten Sie etwas wie eine <f:event type="postInvokeAction" listener="#{bean.reset}"> direkt an die <p:dataTable> angeschlossen haben. Aber dieses Ereignis existiert in JSF 2.2 nicht. OmniFaces hat einen, wird aber nur unter UIViewRoot, UIForm, UIInput und UICommand unterstützt.

Die <f:phaseListener> kommt in der Nähe, aber es wird direkt an UIViewRoot angeschlossen, obwohl Sie es innerhalb <p:dataTable> platzieren. Und es erfordert eine ganze PhaseListener Implementierung.

Die <f:view afterPhase> scheint Ihre beste Wette. Sie benötigen nur eine zusätzliche Überprüfung der Phasen-ID und der Quellkomponente.

<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 könnte bei Bedarf durch eine fest codierte Tabelle Client-ID ersetzt werden)


Ich verstehe, dass dies umständlich ist. Also, für die kommenden OmniFaces 2.2 habe ich altered die vorhandene InvokeActionEventListener, um diesen Anwendungsfall zu unterstützen. Es unterstützt jetzt, an jedem angebracht zu werden.

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

Obwohl es eine nette Lösung ist, denke ich persönlich, dass dies nicht in der UI-Ebene sein sollte. Aber ich habe vielleicht nicht das Wissen um zu sehen, warum es besser sein sollte ... Also bitte erleuchte mich ... niemals zu jung^H^H^H^H^Halt zu lernen – Kukeltje

+0

Du kannst es auch ohne irgendwelche Tags machen die Ansicht, aber dann müssten Sie einige View-spezifische Sachen (IDs und so) in der Bean/Listener fest codieren. Das ist weniger schön. Tags in der Ansicht sind deklarativer und der Controller/das Modell weiß weniger über die Ansicht auf diese Weise. Das ist immer besser :) – BalusC

+0

Das ist nicht was ich meinte. Ich stimme zu, dass der Controller/das Modell so wenig wie nötig (keine?) Über die Ansicht wissen sollte. Ich habe eher davon gesprochen, es in einem 'Basis-Controller' zu tun. Jeder selbst respektierende Entwickler, der PrimeFaces LazyDataModel verwendet, sollte einen haben ... (wenn Sie mehrere Entitäten haben ...). Ich werde versuchen, über das Wochenende eine "Antwort" zu erstellen, um es zu erklären (oder einen Blog daraus zu machen). – Kukeltje

Verwandte Themen