This blog has moved to
http://blog.matthias-reining.com

Die bestehenden Artikel bleiben vorerst alle bei blogspot. Neue Artikel veröffentliche ich allerdings nur noch auf http://blog.matthias-reining.com

Freitag, 7. Mai 2010

JSF 2, AJAX und ein confirm Dialog... (Synchrone Verarbeitung)

Folgendes Problem hat sich bei mir mit dem Setup JSF2.0 und jQuery 1.4 ergeben:
(das Ganze auf Glassfish v3 (daher auch mojarra als JSF Implementierung)
  
Wie erstellt man eine „coole“ Sicherheitsfrage in Verbindung mit einer JSF 2 AJAX Action?
Genauer: wie kann vor dem Aufruf einer JSF 2 commandButton-AJAX-Action einen jQuery UI Dialog blenden, in dem der Klassiker „Wollen Sie wirklcih“ abgefragt wird? 
Auf eine Seite stelle ich eine Tabelle mit ui:repeat dar. Jede Zeile kann dabei editiert werden und auch gelöscht werden. Der Löschvorgang wird durch ein Symbol (‚X‘) am Ende der Zeile dargestellt.

Diese sieht wie folgt aus: 
<td>
      <h:commandButton action="#{schlagView.removeWorking(working.tempIdent)}"
                 image="./img/delete-icon.png"
                 styleClass="listRemove">
            <f:ajax render="@form" execute="@form" />     
      </h:commandButton>
</td>

Funktioniert als AJAX Event perfekt! J 
Um die Usability aber etwas zu steigern, wäre natürlich noch ein Sicherheitshinweis schön.
Per JavaScript lässt sich dieser einfach wie folgt ermitteln: 
<td>
      <h:commandButton onclick="return confirm('Wirklich?')"
                       action="#{schlagView.removeWorking(working.tempIdent)}"
                       image="./img/delete-icon.png"
                       styleClass="listRemove">
            <f:ajax render="@form" execute="@form" />     
      </h:commandButton>
</td>
                                                 
JSF übersetzt beim Rendern die Seite dann entsprechend, so dass auf dem JavaScript onclick-Event folgendes liegt:

onclick="jsf.util.chain(this,event,'return confirm(\' Wirklich\' );','mojarra.ab(this,event,\'action\',\'@form\',\'@form\')');return false"

Hier wird einfach das Event bei ‚NEIN‘ gestoppt und es nichts passiert.

Funktioniert perfekt! J

Um die Usability aber noch etwas mehr zu steigern, wäre natürlich eine gut aussehende Sicherheitsabfrage toll. Eine Sicherheitsabfrage auf Basis eines jQuery UI Confirm Dialogs beispielsweise…

Das Problem hier liegt aber daran, dass in dem jQuery Dialog der Event der Buttons per CallBack Funktion realisiert wird. Dies bedeutet der eigentliche JSF AJAX Aufruf ist dann schon gelaufen. Was man hier benötigt wäre eine synchrone Abarbeitung der Dialog CallBack Funktion zum Aufruf in der JSF commandAction. Mit folgenden Zeilen Code kann man dies bewerkstelligen:

JSF Code: 
<h:commandButton onclick="return removeRow(this);"
                 action="#{schlagView.removeWorking(working.tempIdent)}"
                 image="./img/delete-icon.png"
                 styleClass="listRemove">
      <f:ajax render="@form" execute="@form" />     
</h:commandButton>

JavaScript Code: 
var confirmOk = false;
function removeRow(elem) {
      if (!confirmOk) {
            $('#dialog-confirm').dialog({
                  width:500,
                  modal: true,
                  buttons: {
                        'Freilich': function() {
                             confirmOk=true;
                             $(elem).click();
                             confirmOk=false;
                             $(this).dialog('close');
                        },
                        'Auf keinen Fall': function() {
                             $(this).dialog('close');
                        }
                  }
            });
      }    
      return confirmOk;
};



Hierbei wird vor dem JSF AJAX Call die JavaScript Methode removeRow aufgerufen. Beim ersten Aufruf ist confirmOk == false und somit wird der jQuery Dialog aufgerufen. Die Methode wird aber direkt weiter abgearbeitet und liefert erstmal false zurück, was ein weiteres Aufrufen des JSF AJAX Calls verhindert.
Wird im jQuery Dialog auf ‚Freilich‘ (OK) geklickt, wird die Variable confirmOk auf true gesetzt und das Click-Event des commandButton erneut getriggert ( $(elem).click() ) . Wenn die Methode diesmal durchlaufen wird, liefert sie aber ein true zurück und der JSF AJAX Call wird ausgeführt.

Funktioniert J

Kommentare:

  1. Hi Matthias,

    I benutze PrimeFaces component library. Der ConfirmDialog ist dort automatisch als Komponente dabei. Hier ist ein Demo:

    http://www.primefaces.org:8080/prime-showcase/ui/confirmDialog.jsf

    AntwortenLöschen
  2. Hallo Oleg,
    ich hab mir primefaces mal angeschaut und etwas mit herumexperimentiert - richtig cool :-)
    Da haben es IceFaces oder MyFaces richtig schwer mitzuhalten...

    Bei dem beschriebenen Problem habe ich aber einfach mal versucht, mit reinen Boardmitteln eines AppServes auszukommen (Glassfish & Mojarra). Viele Java Champions machen hier auch Werbung, dass mit Glassfish als AppServer alles vorhanden ist was man braucht - in der Praxis, wenn's dann mal über ein HelloWorld Beispiel rausgeht, wird's dann aber oft ziemlich umständlich (siehe den beschriebenen Workaround in diesem Blog hier).

    Ansonsten - vielen Dank für den Hinweis!
    Primefaces entwickelt sich gerade zu meiner neuen Lieblings-Frontend-Komponente ;-)

    Grüße, Matthias

    AntwortenLöschen