Schlagwörter: ModalPanel Kommentarverlauf ein-/ausschalten | Tastaturkürzel

  • Andreas Höhmann 17:59 am Wednesday, 22. July 2009 Permalink |
    Tags: Appear, Effect, Fadein, Fadeout, ModalPanel, , Scriptaculous   

    Fadein and Fadeout a Richfaces ModalPanel 

    Today i explain you a cool combination for rich:modalPanel and rich:effect.

    In the richfaces forum i found a article about a modalpanel with scriptaculous-effects („fade-in a modalpanel“). The answer was a link to the official richfaces demo-application (photoalbum). There we can find a login-dialog (svn source) with a „appear-effect“:

    <rich:modalPanel id="loginPanel"
    onshow="applyModalPanelEffect('loginPanel', appearFunc,{delay: 0.5, afterFinish: function(){$('loginPanelForm:username').focus();}})"
    styleClass="login-panel"
    showWhenRendered="#{authenticator.loginFailed}"
    width="400" height="150" autosized="true">
    <f:facet name="header">#{messages['login.login']}</f:facet>
    <f:facet name="controls">
    <h:panelGroup id="loginPanelHideControl">
    <h:graphicImage value="/img/modal/close.png" style="cursor:pointer"
    id="loginPanelhidelink" onclick="#{rich:component('loginPanel')}.hide();"/>
    </h:panelGroup>
    </f:facet>
    ...
    <rich:effect type="Appear" name="appearFunc"/>
    ...
    

    The javascript method applyModalPanelEffect can be found in the photoalbum.js (svn source):

    function applyModalPanelEffect(panelId, effectFunc, params) {
     if (panelId && effectFunc) {
     var modalPanel = $(panelId);
     if (modalPanel && modalPanel.component) {
     var component = modalPanel.component;
     var div = component.getSizedElement();
     Element.hide(div);
    effectFunc.call(this, Object.extend({targetId: div.id}, params || {}));}}
    }
    

    With this the rich:modalPanel will not shown immediately … it appears 😉 This was the „fade-in part“.

    I improved the code for the „fade-out part“, first the dialog:

    
    <!-- first the effects -->
    <rich:effect type="Appear" name="appearDialog"/>
     <rich:effect type="Fade" name="disappearDialog"/>
    
    <!-- to keep the dialog-code clean -->
    <c:set var="closeDialog" value="hideModalPanelWithEffect('myDialog',disappearDialog,{delay:0.1,duration:0.5})"/>
    
    <rich:modalPanel id="myDialog"
     onshow="showModalPanelWithEffect('myDialog',appearDialog,{delay:0.1,duration:0.5})"
     width="610" height="350" minHeight="350" autosized="true" shadowDepth="0">
    <f:facet name="controls">
    <h:panelGroup>
    <h:graphicImage value="/img/modal/close.png" style="cursor:pointer" onclick="#{closeDialog}"/>
    </h:panelGroup>
    </f:facet>
    </rich:modalPanel>
    

    and the javascript:

    function applyModalPanelEffect(panelId, effectFunc, params, hide) {
     if (panelId && effectFunc) {
     var modalPanel = $(panelId);
     if (modalPanel && modalPanel.component) {
     var component = modalPanel.component;
     var div = component.getSizedElement();
     if (hide) {
     Element.hide(div);
     }
     effectFunc.call(this, Object.extend( {targetId : div.id}, params || {}));}}
    }
    
    function showModalPanelWithEffect(panelId, showEffect, params) {
     applyModalPanelEffect(panelId, showEffect, params, true);
    }
    
    function hideModalPanelWithEffect(panelId, hideEffect, params) {
     var _params = params;
    _params['afterFinish'] = function(){Richfaces.hideModalPanel(panelId)};
     applyModalPanelEffect(panelId, hideEffect, params, false);
    }
    

    Now the dialog call showModalPanelWithEffect to fade-in and hideModalPanelWithEffect to fade-out.

    Try it 😀

     
  • Andreas Höhmann 17:13 am Monday, 22. June 2009 Permalink |
    Tags: Input, , ModalPanel, Reset,   

    Clear JSF Input Components 

    Beim Implementieren einer einfachen CRUD Anwendung mit Hilfe von Richfaces Datatable und ModalPanel bin ich über ein „Problem“ mit validierten (leeren) Eingabefeldern gestolpert.

    Das Problem ist eigentlich kein richtiges Problem, sondern das Standardverhalten von JSF 🙂 Unschön wird es wenn man einen rich:modalPanel als Edit-Dialog einsetzt und diesen wiederverwendet.

    Der grobe Aufbau:

    • eine DataTable zeigt eine Liste von Entities (z.B. mit Hilfe eine DAOs geladen)
    • jedes Entity hat eine eindeutige ID (z.B. PrimaryKey aus JPA)
    • pro Tabellenzeile gibt es einen „Edit“-CommandLink der eine rich:modalPanel für das Editieren eines Entity öffnet
    • vor jedem Edit muss die gewünschte Entity in einen CrudManager (Session-Scoped Bean) gelangen, aus der sich der Edit-Dialog mit Daten versorgen kann und mit dessen Hilfe die eigentliche Edit-Aktion durchgeführt wird

    Nun sollen bestimmte Eingabefelder im Edit-Dialog validiert werden (z.B. mit einer @NotEmpty Annotation an den ensprechenden Properties der Entitiy-Klasse). Wenn man nun den Dialog für eine Entity mir der ID ‚1‘ öffnet und eine Validierungsfehler auslöst, z.B. durch das Abschicken mit leeren Eingabefeldern, wird dieser Fehler ausgegeben … soweit so gut. Der Dialog kann dann geschlossen werden. Soll nun Entity mit der ID ‚2‘ mit dem gleichen Dialog editiert werden, sind die Eingabefelder immer noch leer und nicht wie gewünscht mit den Werten aus Entity-2 gefüllt. Warum?!

    Nach einer kurzen Googlesuche landete ich auf der Seite http://wiki.apache.org/myfaces/ClearInputComponents die den Effekt beschreibt. Der Grund für das Verhalten ist die Zwischenspeicherung von „SubmitedValues“ in den jeweiligen UIComponents (z.B. h:inputText). Die werden den eigentlichen Modeldaten vorgezogen.

    Will man nun einen immer aktuellen Edit-Dialog haben, gibt es verschiedene Möglichkeiten (siehe MyFaces). Ich habe mich für die „radikal einfache“ Lösung entschieden … lösche alle Elemente innerhalb des Edit-Dialogs und lasse sie immer neu erzeugen.

    Die Entity-Liste besteht aus einer rich:dataTable, pro Zeile ein a4j:commandButton:

    
    <rich:dataTable value="#{tableManager.model}" var="dataItem">
    
    <!-- Edit-Command Column -->
    <rich:column sortable="false">
    <a4j:commandButton ajaxSingle="true" limitToList="true"
    reRender="foobar_editPanel"
    oncomplete="Richfaces.showModalPanel('foobar_editPanel')"
     actionListener="#{crudManager.onEdit}">
     <f:attribute name="onEditClearTarget" value="foobar_editPanel"/>
     <f:setPropertyActionListener value="#{dataItem}" target="#{crudManager.currentEntity}" />
    </a4j:commandButton>
    
    <!-- more Columns ... -->
    </rich:dataTable>
    
    

    Der tableManager liefert die Entity-Daten, also eine Liste von Entity-Beans, jede Bean hat eine eindeutige ID. Der crudManager enthält stellt die gesamte CRUD Funktionalität zur Verfügung. Für eine Edit muss er mit einer Entity „initialisiert“ werden, dies geschieht via f:setPropertyActionListener. Das reRender bewirkt, dass der Edit-Dialog aktuallisiert wird.

    Der Edit-Dialog wird mit Hilfe von rich:modalPanel erzeugt (foobar_editPanel) und enthält eine Reihe von h:inputText Elementen. Diese sind wiederum an den crudManager gebunden.

    Der Code für das Zurücksetzen der Inputelemente im Edit-Dialog ist ebenfalls im crudManager verborgen und sieht folgendermaßen aus:

    
    public abstract class AbstractCrudManager {
    
    public static final String ONEDIT_ATTRIBUTE_CLEARTARGET = "onEditClearTarget"; //$NON-NLS-1$
    
    /**
    <ul>
    <li>Event-handler will be triggered on <tt>edit</tt>. This method is used as a</li>
    <li>{@link ActionListener} and will be called before a <tt>edit-view</tt> is</li>
    <li>shown. So here we can do some "initializations" for the edit-view, i.e.</li>
    <li>reset input-fields.</li>
    <li></li>
    <li></li>
    <li>This base implementation will call {@link #clearEditTarget(UIComponent)}.</li>
    <li></li>
    <li></li>
    <li>@param aEvent</li>
    </ul>
    
    
     *          is never <code>null</code>
     */
    public void onEdit(final ActionEvent aEvent) {
    clearEditTarget(aEvent.getComponent());
     }
    
    /**
    <ul>
    <li>This method handle a edit-form-clear. Per default the command-button which delegates to the</li>
    <li>edit-view could have a attribute {@link #ONEDIT_ATTRIBUTE_CLEARTARGET}.</li>
    <li></li>
    <li>@param theSourceComponent</li>
    </ul>
    
    
     *          is never <code>null</code>
     */
     protected void clearEditTarget(final UIComponent theSourceComponent) {
     final String onEditTarget = (String) theSourceComponent.getAttributes().get(ONEDIT_ATTRIBUTE_CLEARTARGET);
     if (onEditTarget == null) {
     return;
     }
     final UIComponent editTarget = FacesContext.getCurrentInstance().getViewRoot().findComponent(onEditTarget);
     if (editTarget == null) {
     return;
     }
     editTarget.getChildren().clear();
     }
    
    ...
    
    }
    
    

    Damit ist auch klar was das <f:attribute name=“onEditClearTarget“ value=“#{id}_editPanel“/> bewirkt … es definiert die UI-Komponente die vor dem Öffnen des Dialogs zurückgesetzt werden soll.

    Damit wird bei jedem Klick auf „Edit“ ein Ajax-Request zum Server geschickt, dort wird die aktuelle Entity in den crudManager hinterlegt, es wird onEdit aufgerufen und damit der Inhalt des Edit-Dialogs gelöscht. JSF sorgt dann beim RenderResponse wieder dafür, dass alle UI Componenten korrekt erzeugt werden. Da dann alle Eingabeelement noch vollkommen „neu“ sind, zeigen diese auch die Werte aus dem Modell an.

     
c
Neuen Beitrag erstellen
j
nächster Beitrag/nächster Kommentar
k
vorheriger Beitrag/vorheriger Kommentar
r
Antworten
e
Bearbeiten
o
zeige/verstecke Kommentare
t
Zum Anfang gehen
l
zum Login
h
Zeige/Verberge Hilfe
Shift + ESC
Abbrechen