Mantener p: diálogo abierto cuando se produce un error de validación después de enviar


Diálogo de ejemplo mínimo:

<p:dialog header="Test Dialog"  
          widgetVar="testDialog"> 
  <h:form> 
    <p:inputText value="#{mbean.someValue}"/> 

    <p:commandButton value="Save" 
                     onsuccess="testDialog.hide()" 
                     actionListener="#{mbean.saveMethod}"/> 
  </h:form>       
</p:dialog> 

Lo que quiero ser capaz de hacer es tener el mbean.saveMethod de alguna manera evita que el diálogo se cierre si hubo algún problema y solo genera un mensaje a través de growl. Este es un caso en el que un validador no ayudará porque no hay forma de saber si someValue es válido hasta que se envíe un guardado a un servidor back-end. Actualmente hago esto usando el atributo visible y lo apunto a un campo booleano en mbean. Eso funciona, pero hace que la interfaz de usuario más lento porque subir o bajar el cuadro de diálogo requiere golpear el servidor.

Author: BalusC, 2012-02-08

6 answers

El onsuccess se ejecuta si la solicitud ajax en sí tuvo éxito (es decir, no hay error de red, excepción no capturada, etc.), no si el método de acción se invocó con éxito.

Dado un <p:dialog widgetVar="testDialog"> Podría eliminar el onsuccess y reemplazarlo por PrimeFaces RequestContext#execute() dentro de saveMethod():

if (success) {
    RequestContext.getCurrentInstance().execute("PF('testDialog').hide()");
}

Nota: PF() se introdujo en PrimeFaces 4.0. En versiones anteriores de PrimeFaces, necesita testDialog.hide() en su lugar.

Si prefiere no saturar el controlador con scripts específicos de la vista, puede usar oncomplete en su lugar, que ofrece un objeto args que tiene una propiedad booleana validationFailed:

<p:commandButton ...
    oncomplete="if (args &amp;&amp; !args.validationFailed) PF('testDialog').hide()" />

La verificación if (args) es necesaria porque puede estar ausente cuando se ha producido un error ajax y, por lo tanto, causar un nuevo error JS cuando intenta obtener validationFailed de ella; el &amp; en lugar de & es obligatorio por la razón explicada en esta respuesta , refactorizar si es necesario a una función JS que invoque como oncomplete="hideDialogOnSuccess(args, testDialog)" como se muestra en Mantenga

abierto cuando la validación failed .

Esta última solución (con un poco de reescritura) debería funcionar para jsf simple h:commandButton en combinación con un f:ajax


Es desafortunado que PrimeFaces no soporte lo que RichFaces ya soporta: reevaluación de tiempo de solicitud de EL en atributos on*. De lo contrario también sería capaz de hacer precisamente esto:

<p:commandButton ...
    oncomplete="if (#{not facesContext.validationFailed}) PF('testDialog').hide()" /> 
 141
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-24 16:24:35

Acabo de buscar en Google esta solución. Básicamente, la idea es usar ActionListener en lugar de la acción de button, y en backing bean agregas el parámetro callback que luego se registrará en el método oncomplete de button. Código parcial de muestra:

JSF primero:

<p:commandButton actionListener="#{myBean.doAction}"
   oncomplete="if (!args.validationFailed &amp;&amp; args.saved) schedulesDialog.hide();" />

Frijol de respaldo:

public void doAction(ActionEvent actionEvent) {
    // do your stuff here...
    if (ok) {
        RequestContext.getCurrentInstance().addCallbackParam("saved", true);
    } else {
        RequestContext.getCurrentInstance().addCallbackParam("saved", false);
    }
}

Espero que esto ayude a alguien:)

 16
Author: Maciej Szulik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-13 08:01:17

Usar el atributo oncomplete de su botón de comando y un script realmente simple le ayudará mucho.

El diálogo y el botón de comando serían algo similar a esto:

<p:dialog widgetVar="dialog">
   <h:form id="dialogView">
       <p:commandButton id="saveButton" icon="ui-icon-disk"
           value="#{ui['action.save']}"
           update=":dataList :dialogView"
           actionListener="#{mbean.save()}"
           oncomplete="handleDialogSubmit(xhr, status, args)" />
   </h:form>
 </p:dialog>

Un script sería algo como esto:

<script type="text/javascript">
    function handleDialogSubmit(xhr, status, args) {
        if (args.validationFailed) {
            dialog.show();
        } else {
            dialog.hide();
        }
    }
</script>
 15
Author: Alonso Dominguez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-08 16:08:55

Uso esta solución:

Código JSF:

<p:dialog ... widgetVar="dlgModify" ... >
...
<p:commandButton value="Save" update="@form" actionListener="#{AdminMB.saveTable}" />
<p:commandButton value="Cancel" oncomplete="PF('dlgModify').hide();"/>

Código de frijol de respaldo:

public void saveTable() {
    RequestContext rc = RequestContext.getCurrentInstance();
    rc.execute("PF('dlgModify').hide()");
}
 7
Author: Antaeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-29 11:43:40

Creo que esta es la solución más limpia. Al hacer esto, no necesita cambiar su código de botones. Esta solución anula el prototipo de función hide.

$(document).ready(function() {
    PrimeFaces.widget.Dialog.prototype.originalHide = PrimeFaces.widget.Dialog.prototype.hide; // keep a reference to the original hide()
    PrimeFaces.widget.Dialog.prototype.hide = function() {
        var ajaxResponseArgs = arguments.callee.caller.arguments[2]; // accesses oncomplete arguments
        if (ajaxResponseArgs && ajaxResponseArgs.validationFailed) {
            return;  // on validation error, prevent closing
        }
        this.originalHide();
    };
});

De esta manera, puede mantener su código como:

<p:commandButton value="Save" oncomplete="videoDetalheDialogJS.hide();" 
   actionListener="#{videoBean.saveVideo(video)}" />
 3
Author: Luís Soares,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-17 20:07:28

La solución más fácil es no tener ningún "widget.hide", ni en onclick, ni en oncomplete. Elimine las funciones de ocultar y simplemente ponga

visible="#{facesContext.validationFailed}" 

Para la etiqueta de diálogo

 0
Author: makkasi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-11 15:27:46