web-dev-qa-db-ger.com

Ausführungsreihenfolge der Ereignisse beim Drücken von PrimeFaces p: commandButton

Ich versuche, eine JSF2-Bean-Methode auszuführen und nach Abschluss der Methode durch Klicken auf PrimeFaces <p:commandButton> Ein Dialogfeld anzuzeigen.

<p:commandButton id="viewButton" value="View"
    actionlistener="#{userBean.setResultsForSelectedRow}" ajax="false"
    update=":selectedRowValues"
    oncomplete="PF('selectedRowValuesDlg').show()">
</p:commandButton>
<p:dialog id="selectedRowValues" widgetVar="selectedRowValuesDlg" dynamic="true">
    <h:outputText value="#{userBean.selectedGroupName}" />
</p:dialog>

Wenn ich auf die Befehlsschaltfläche klicke, wird die Bean Action Listener-Methode setResultsForSelectedRow ordnungsgemäß ausgeführt, aber das Dialogfeld wird nach Abschluss der Methode nicht angezeigt. Wenn ich actionlistener entferne, wird das Dialogfeld angezeigt. Ich weiß nicht, was falsch läuft.

Was ist die Ausführungsreihenfolge von Ereignissen? Ist es möglich, actionlistener und oncomplete gleichzeitig auszuführen?

31
Abhay

Es ist fehlgeschlagen, weil Sie ajax="false" Verwendet haben. Dies löst eine vollständige synchrone Anforderung aus, die wiederum ein Neuladen der gesamten Seite verursacht, wodurch die oncomplete niemals ausgelöst wird (beachten Sie, dass alle anderen Ajax-bezogenen Attribute wie process, onstart , onsuccess, onerror und update werden ebenfalls niemals abgefeuert.

Dass es beim Entfernen von actionListener geklappt hat, ist ebenfalls unmöglich. Es hätte genauso scheitern sollen. Vielleicht haben Sie auch ajax="false" Entfernt, ohne wirklich zu verstehen, was Sie getan haben. Das Entfernen von ajax="false" Sollte tatsächlich die gewünschte Anforderung erfüllen.


Ist es auch möglich, actionlistener und oncomplete gleichzeitig auszuführen?

Nein. Das Skript kann nur ausgelöst werden vor oder nach dem Aktionslistener. Sie können onclick verwenden, um das Skript zum Zeitpunkt des Klickens auszulösen. Sie können onstart verwenden, um das Skript zu dem Zeitpunkt auszulösen, zu dem die Ajax-Anforderung gesendet werden soll. Aber sie werden niemals genau gleichzeitig abgefeuert. Die Reihenfolge ist wie folgt:

  • Benutzer klickt auf die Schaltfläche im Client
  • onclick JavaScript-Code wird ausgeführt
  • JavaScript bereitet eine Ajax-Anforderung basierend auf process und dem aktuellen HTML-DOM-Baum vor
  • onstart JavaScript-Code wird ausgeführt
  • JavaScript sendet eine Ajax-Anfrage vom Client zum Server
  • JSF ruft eine Ajax-Anfrage ab
  • JSF verarbeitet den Anforderungslebenszyklus im JSF-Komponentenbaum basierend auf process.
  • actionListener JSF-Backing-Bean-Methode wird ausgeführt
  • action JSF-Backing-Bean-Methode wird ausgeführt
  • JSF bereitet eine Ajax-Antwort basierend auf update und dem aktuellen JSF-Komponentenbaum vor
  • JSF sendet eine Ajax-Antwort vom Server zum Client
  • JavaScript ruft Ajax-Antwort ab
    • wenn der HTTP-Antwortstatus 200 ist, wird onsuccess JavaScript-Code ausgeführt
    • andernfalls wird bei einem HTTP-Antwortstatus von 500 onerror JavaScript-Code ausgeführt
  • JavaScript führt update basierend auf der Ajax-Antwort und dem aktuellen HTML-DOM-Baum aus
  • oncomplete JavaScript-Code wird ausgeführt

Beachten Sie, dass update ausgeführt wird afteractionListener, wenn Sie also onclick oder onstart verwenden, um den Dialog anzuzeigen In diesem Fall werden möglicherweise immer noch alte Inhalte anstelle von aktualisierten Inhalten angezeigt, was für die Benutzererfahrung schlecht ist. Verwenden Sie stattdessen oncomplete, um den Dialog anzuzeigen. Beachten Sie auch, dass Sie action anstelle von actionListener verwenden sollten, wenn Sie eine Geschäftsaktion ausführen möchten.

Siehe auch:

126
BalusC

Ich liebe es einfach, Informationen zu bekommen, wie sie BalusC hier gibt - und er ist so freundlich, SO vielen Menschen mit so GUTEN Informationen zu helfen, dass ich seine Worte als Evangelium betrachte, aber ich war nicht in der Lage, diese Reihenfolge der Ereignisse zu nutzen Lösen Sie diese Art von Timing-Problem in meinem Projekt. Da BalusC hier eine großartige allgemeine Referenz anbrachte, die ich sogar mit einem Lesezeichen versehen habe, dachte ich, ich würde meine Lösung für einige fortgeschrittene Timing-Probleme an derselben Stelle spenden, da dies auch die Timing-Probleme des ursprünglichen Posters löst. Ich hoffe dieser Code hilft jemandem:

        <p:pickList id="formPickList" 
                    value="#{mediaDetail.availableMedia}" 
                    converter="MediaPicklistConverter" 
                    widgetVar="formsPicklistWidget" 
                    var="mediaFiles" 
                    itemLabel="#{mediaFiles.mediaTitle}" 
                    itemValue="#{mediaFiles}" >
            <f:facet name="sourceCaption">Available Media</f:facet>
            <f:facet name="targetCaption">Chosen Media</f:facet>
        </p:pickList>

        <p:commandButton id="viewStream_btn" 
                         value="Stream chosen media" 
                         icon="fa fa-download"
                         ajax="true"
                         action="#{mediaDetail.prepareStreams}"                                              
                         update=":streamDialogPanel"
                         oncomplete="PF('streamingDialog').show()"
                         styleClass="ui-priority-primary"
                         style="margin-top:5px" >
            <p:ajax process="formPickList"  />
        </p:commandButton>

Das Dialogfeld befindet sich außerhalb dieses Formulars am oberen Rand von XHTML und verfügt über ein eigenes, in das Dialogfeld eingebettetes Formular sowie eine Datentabelle, die zusätzliche Befehle zum Streamen der Medien enthält, die zum Zeitpunkt des Dialogfelds vorbereitet und einsatzbereit sein mussten vorgestellt. Mit derselben Technik können Sie beispielsweise benutzerdefinierte Dokumente herunterladen, die vorbereitet werden müssen, bevor sie über die Schaltflächen fileDownload im Dialogfeld auf den Computer des Benutzers übertragen werden.

Wie gesagt, dies ist ein komplizierteres Beispiel, aber es trifft alle Höhepunkte Ihres und meines Problems. Wenn Sie auf die Befehlsschaltfläche klicken, wird zunächst sichergestellt, dass die Backing-Bean mit den Ergebnissen der Auswahlliste aktualisiert wird. Anschließend wird die Backing-Bean angewiesen, anhand ihrer Auswahl in der Auswahlliste Streams für den Benutzer vorzubereiten und anschließend die Steuerelemente in zu aktualisieren Zeigen Sie dann das Dialogfeld an, in dem der Benutzer mit dem Streaming des Inhalts beginnen kann.

Der Trick dabei war, die Ereignisreihenfolge von BalusC für den Hauptbefehls-Button zu verwenden und dann das Bit <p:ajax process="formPickList" /> Hinzuzufügen, um sicherzustellen, dass es zuerst ausgeführt wurde passiert nicht für mich, bevor ich es hinzufügte). Also, ja, dieser CommandButton rockt, weil Sie sowohl frühere, ausstehende und aktuelle Komponenten als auch die Backing Beans beeinflussen können - aber das Timing, um alle miteinander in Beziehung zu setzen, ist manchmal nicht einfach in den Griff zu bekommen.

Viel Spaß beim Codieren!

8
FreedomRings