2015-08-17 12 views
13

Podczas wykonywania operacji CRUD przy użyciu JSF/PrimeFaces, zazwyczaj potrzebna jest wspólna metoda, która resetuje pola/właściwości fasoli zarządzanej, która ma być wywoływana zasadniczo po pomyślnym wykonaniu jednej takiej operacji zakończone tak, że pola w komponencie bean są resetowane do ich początkowej (domyślnej) wartości.Potencjalna metoda wywołująca po spełnieniu żądania POST (w zasadzie Ajaxical)

kod urojona:

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

Sposób submit() wykonaniu "wpisać" jest zasadniczo związana z JSF/PrimeFaces elementów sterujących, takich jak <p/h:commandButton> lub <p/h:commandLink>. Jak na przykład. związane z <p:dataTable>

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

następujące zdarzenia AJAX wymaga również, aby wywołać metodę 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}"/> 

Jak widać, metoda reset() musi być zapamiętany dokładnie jak to jest wywoływana z kilku miejscach. Droga jest nieco trudna do utrzymania.

Czy istnieje sposób automatycznego wywołania takiej wspólnej metody po tym, jak każde żądanie POST wykonujące jedną z operacji CRUD zakończyło pomyślnie swoje zadanie?

+0

Wystarczy, aby mieć pewność, że jesteś świadomy, że można podać wiele wartości w 'event' atrybutu? Na przykład: ''. Wydaje mi się, że wszystkie pozostałe atrybuty są również identyczne. – BalusC

+0

Tak, pozostałe atrybuty są identyczne (chociaż 'reset()' musi być wywoływany ręcznie z komponentu bean podczas wstawiania, usuwania.Myślę, aby również wyłączyć te połączenia, jeśli to możliwe). – Tiny

+0

Tylko dla pewności, czy jest to * po * każdej prośbie o dodanie do wydarzenia lub * o * każdej prośbie o dodanie do wydarzenia? Wygląda na to, że teraz to drugie, prawda? – Kukeltje

Odpowiedz

8

JSF nie ma żadnych tagów dla tego.

Idealnie chciałbyś mieć coś takiego jak <f:event type="postInvokeAction" listener="#{bean.reset}"> bezpośrednio dołączony do <p:dataTable>. Ale to wydarzenie nie istnieje w JSF 2.2. OmniFaces ma jeden, ale jest obsługiwany tylko na UIViewRoot, UIForm, UIInput i UICommand.

Zbliża się <f:phaseListener>, ale zostaje bezpośrednio przyłączony do UIViewRoot, nawet jeśli umieścisz go wewnątrz <p:dataTable>. Wymaga to całej implementacji PhaseListener.

Model <f:view afterPhase> wydaje się być najlepszym rozwiązaniem. Potrzebujesz jedynie dodatkowego sprawdzenia identyfikatora fazy i komponentu źródłowego.

<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 mógłby ewentualnie być zastąpiona przez zakodowanego na stałe tabeli ID klienta)


Rozumiem, że jest to niewygodne. Tak więc, dla nadchodzącego OmniFaces 2.2 mam altered istniejący, aby obsługiwać również ten przypadek użycia. Teraz obsługuje on dołączanie na dowolnym UIComponent.

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

Mimo że jest to przyjemne rozwiązanie, osobiście uważam, że nie powinno to być w warstwie interfejsu użytkownika. Ale może nie mam wiedzy, aby zobaczyć, dlaczego lepiej powinno być ... Więc proszę mnie oświecić ... nigdy do młodości^H^H^H^H^Trzymaj się uczyć – Kukeltje

+0

Możesz to również zrobić bez żadnych tagów widoku, ale wtedy trzeba będzie zaszyfrować niektóre rzeczy związane z widokiem (identyfikatory i tym podobne) w komponencie bean/listener. To mniej miłe. Znaczniki w widoku są bardziej deklaratywne, a kontroler/model mniej wie o widoku w ten sposób. To zawsze lepsze :) – BalusC

+0

Nie o to mi chodziło. Zgadzam się, że kontroler/model powinien znać tak mało, jak potrzeba (brak?) Na temat widoku. Mówiłem raczej o zrobieniu tego w "kontrolerze bazowym" Każdy szanujący się programista korzystający z PrimeFaces LazyDataModel powinien mieć ... (jeśli masz wiele obiektów ...). Spróbuję stworzyć "odpowiedź" na weekend, aby wyjaśnić (lub zrobić z tego bloga). – Kukeltje

Powiązane problemy