webentwicklung-frage-antwort-db.com.de

Aktualisieren des gesamten <p: dataTable> nach Abschluss von <p: ajax event = "cellEdit">

Ich habe Schwierigkeiten, eine PrimeFaces-Datentabelle erneut zu rendern, nachdem eine Zelle bearbeitet wurde. Wenn Sie den Wert in einer Zelle ändern, werden möglicherweise Einträge in den anderen Zellen geändert. Daher muss die gesamte Tabelle aktualisiert werden. 

Hier ist die JSF-Seite:

<h:form id="testForm">
    <p:outputPanel id="testContainer">

        <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

            <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

            <p:column headerText="Col1">  
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col1}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col1}" /></f:facet>
                </p:cellEditor> 
            </p:column>

            <p:column headerText="Col2">
                <p:cellEditor>
                    <f:facet name="output"><h:outputText value="#{entry.col2}" /></f:facet>
                    <f:facet name="input"><p:inputText value="#{entry.col2}" /></f:facet>
                </p:cellEditor>  
            </p:column>

        </p:dataTable>

        <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />

    </p:outputPanel>                                    
</h:form>

Und hier ist die Stützbohne:

@ManagedBean(name = "tableBean", eager = false)
@ViewScoped 
public class TableBean {

    public TableBean() {
        RowData entry = new RowData("a1", "b1");
        entries.add(entry);
        entry = new RowData("a2", "b2");
        entries.add(entry);
        entry = new RowData("a3", "b3");
        entries.add(entry);
    }

    public class RowData {

        private String col1;
        private String col2;

        public RowData(String col1, String col2) {
            this.col1 = col1;
            this.col2 = col2;
        }

        public String getCol1() {
            return col1;
        }

        public void setCol1(String col1) {
            this.col1 = col1;
        }

        public String getCol2() {
            return col2;
        }

        public void setCol2(String col2) {
            this.col2 = col2;
        }
    }

    private ArrayList<RowData> entries = new ArrayList<RowData>();

    public List<RowData> getData() {
        return entries;
    }

    public void onCellEdit(CellEditEvent event) {
        entries.get(event.getRowIndex()).setCol1("Dummy Col 1");
        entries.get(event.getRowIndex()).setCol2("Dummy Col 2");        
    }   
}

Wenn Sie update = ": testForm: testContainer" in das cellEdit AJAX -Ereignis einschließen, werden durch das Ändern eines Zellenwerts die Daten auf dem Bildschirm gelöscht und nur der Zelleninhalt (zusammen mit der Schaltfläche) dargestellt . Wenn das Aktualisierungsattribut nicht angegeben ist, bleibt die Tabelle auf dem Bildschirm, und die aktive Zelle wird aktualisiert, aber keine der anderen Zellen wird aktualisiert (wie erwartet).

Das gewünschte Verhalten kann (auf nicht automatisierte Weise) erreicht werden, indem das Aktualisierungsattribut im cellEdit-Ereignis AJAX nicht angegeben wird und nach dem Bearbeiten eines Zellenwerts auf die Schaltfläche Neu anzeigen geklickt wird. Wie kann ich dies automatisiert erreichen und warum funktioniert das Aktualisierungsattribut nicht wie erwartet?

Ich verwende PrimeFaces 4.0.

31
Franzl

Bei den rowEdit- und cellEdit-Ereignissen wird in der Tabelle nicht beabsichtigt, etwas anderes als die aktuelle Zeile zu aktualisieren oder erneut zu rendern, auch wenn dies nicht ausdrücklich im update-Attribut angegeben ist. Dies ist die Folge des etwas übereifrigen Versuchs von PrimeFaces, die Antwortgröße zu minimieren. In den meisten Fällen ist dies sinnvoll, in Ihrem Fall jedoch nicht. Es ist eine Ausgabe wert. 

In der Zwischenzeit verwenden Sie <p:remoteCommand>, um die gewünschte Listener-Methode aufzurufen und eine vollständige Aktualisierung der Tabelle durchzuführen, bis das Problem behoben ist.

Umschreiben

<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />
    ...
</p:dataTable>

zu

<p:remoteCommand name="onCellEdit" action="#{tableBean.onCellEdit}" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
55
BalusC

Die BaLusC-Lösung hat für mich nicht direkt funktioniert. Das onCellEdit benötigt ein CellEditEvent als Parameter. Mein Workaround ist wie folgt:

<p:remoteCommand name="onCellEdit" update="testContainer" />
<p:dataTable ...>
    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" oncomplete="onCellEdit()" />
    ...
</p:dataTable>
20
Tim Long

Wenn keine der Lösungen für Sie funktioniert hat, hat dies für mich funktioniert

<p:dataTable ... id="theId" widgetVar="theWidget" ...>
                <p:ajax event="rowEdit" listener="#{...}"
                        oncomplete="PF('theWidget').filter()"/> 
....

Ich rufe die Filtermethode für das PF-Widget auf ajax complete auf. Jede Methode, die ein "Neuladen" der Tabelle ausführt, sollte funktionieren. Ich habe Filter verwendet, da meine Tabelle Spaltenfilter enthielt.

5
Lance Reid

Ich habe deinen Code getestet. Zuerst habe ich p: commandButton aus p: outputPanel verschoben. Hier ist modifizierter Code:

<h:form id="testForm">
            <p:outputPanel id="testContainer">

                <p:dataTable id="testTable" value="#{tableBean.data}" var="entry" editable="true" editMode="cell">

                    <p:ajax event="cellEdit" listener="#{tableBean.onCellEdit}" update=":testForm:testContainer" />

                    (...)

                </p:dataTable>
            </p:outputPanel>
            <p:commandButton id="refreshButton" value="Redisplay" update="testContainer" />
        </h:form>

Ich denke, dass dieser Code nicht richtig funktioniert. Wenn Sie etwas in der Tabelle ändern, rendert der p: ajax jedes Mal die volle Tabelle. Das Programm lädt also grundlegende Daten aus dem TableBean-Konstruktor und löscht neue Daten.

basic data

Wenn ich Ihren p: ajax-Code weglasse, werden keine neuen Daten vom Bildschirm verschwindet. Die Variable refreshButton p: commandButton funktioniert ordnungsgemäß.

Wenn Sie update = ": testForm: testContainer" in cellEdit .__ einschließen. AJAX - Ereignis, wenn ein Zellenwert geändert wird, werden die auf dem Bildschirm angezeigten Daten gelöscht und rendert nur den Zellinhalt (zusammen mit der Schaltfläche) - nicht verstehe, warum das so ist.

Ich denke, es ist ein schlechtes Design, fügen Sie update=":testForm:testContainer" zu ajax hinzu, weil es Ihr outputPanel mehr als nur ein Update ausführt (das erste Mal korrekt funktioniert, das zweite Mal konnte die Zelle nicht bearbeiten, da das Programm viele Male die Tabelle aktualisiert). 

Ich weiß nicht, was dein Ziel ist. Wenn Sie eine Tabelle ohne Befehlsschaltfläche rendern möchten, können Sie ein Javascript-Ereignis oder eine p: -Meldung angeben.

Ich denke, wenn Sie das Update in p: ajax weglassen oder das Update einer p: -Meldung angeben und p.commandButton aus testContainer verschieben, funktioniert der Code ordnungsgemäß.

0
herry

Nach 5 Jahren besteht dieses Problem immer noch. Während die Lösung von Baukes äußerst hilfreich ist und wichtige Erkenntnisse enthält, ist sie leider noch unvollständig, wie LtlBeBoy bereits in seinem Kommentar hervorgehoben hat. Nachfolgende Änderungen ohne Änderung führen zu einem inkonsistenten Tabellenstatus, in dem keine weiteren Änderungen mehr möglich sind. Der Grund ist, dass das oncomplete-Fernupdate kommt, nachdem der Bearbeitungsmodus der neuen Zelle bereits aktiviert ist. Der Editiermodus der neuen Zelle wird also durch das Update zerstört. Das Update kann jedoch nicht im Ajax-Listener tableBean#onCellEdit durchgeführt werden, da dies die Tabelle fälschlicherweise nur mit einer Zelle anzeigen würde.

Die Lösung ist, das Update im Remote-Befehl-Listener auszuführen und nur, wenn eine Änderung eingetreten ist. In tableBean implementieren Sie also eine programmgesteuerte Aktualisierung, einen Remote-Listener und ein Flag, das auf Änderungen hinweist:

public static void update(String id) {
   PrimeFaces pf = PrimeFaces.current(); //RequestContext.getCurrentInstance() for <PF 6.2
   if(pf.isAjaxRequest()) pf.ajax().update(id);
}

/** Whether onCellEdit changed the value */
boolean onCellEditChange;

public void onCellEditRemote() { 
    if(!onCellEditChange) update("testContainer");
}

public void onCellEdit(CellEditEvent event) {
    ...  onCellEditChange= /*Change happend*/ ...
}

Der Remote-Befehl hat kein Update-Attribut mehr:

<p:remoteCommand name="onCellEdit" actionListener="#{tabelBean.onCellEditRemote}"/>
0
Marc Dzaebel