web-dev-qa-db-fra.com

Maintenir p: dialogue ouvert lorsqu'une erreur de validation survient après l'envoi

Exemple de dialogue minimal:

<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> 

Ce que je veux pouvoir faire, c’est que mbean.saveMethod empêche d’une manière ou d’une autre la fermeture de la boîte de dialogue s’il y avait un problème et ne produisait un message qu’à travers un grondement. Dans ce cas, un validateur n’aidera pas car il n’ya aucun moyen de savoir si une valeur est valide tant qu’une sauvegarde n’a pas été soumise à un serveur principal. Actuellement, je le fais en utilisant l'attribut visible et le pointe vers un champ booléen dans mbean. Cela fonctionne mais rend l'interface utilisateur plus lente, car le fait d'afficher ou de masquer la boîte de dialogue nécessite d'appuyer sur le serveur.

63
JOTN

onsuccess s'exécute si la demande ajax a abouti (c'est-à-dire qu'il n'y a pas d'erreur de réseau, d'exception non capturée, etc.), et non si la méthode d'action a été invoquée avec succès.

Avec un <p:dialog widgetVar="testDialog"> Vous pouvez supprimer le onsuccess et le remplacer par PrimeFaces RequestContext#execute() dans saveMethod():

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

Remarque: PF() a été introduit dans PrimeFaces 4.0. Dans les versions antérieures de PrimeFaces, vous avez plutôt besoin de testDialog.hide().

Si vous préférez ne pas encombrer le contrôleur avec des scripts spécifiques à la vue, vous pouvez utiliser oncomplete qui propose un objet args avec une propriété booléenne validationFailed:

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

La vérification if (args) est nécessaire, car elle peut être absente lorsqu'une erreur ajax s'est produite et donc générer une nouvelle erreur JS lorsque vous essayez d'obtenir validationFailed; le &amp; au lieu de & est obligatoire pour la raison expliquée dans cette réponse , refactor si nécessaire à une fonction JS que vous appelez comme oncomplete="hideDialogOnSuccess(args, testDialog)" comme indiqué dans Laissez <p: dialogue> ouvert en cas d'échec de la validation .

Cette dernière solution (avec un peu de réécriture) devrait fonctionner pour plain jsf h:commandButton En combinaison avec un f:ajax


Il est regrettable que PrimeFaces ne prenne pas en charge ce que RichFaces prend déjà en charge: la réévaluation à la requête de EL dans les attributs on*. Sinon, vous pourriez aussi faire ceci:

<p:commandButton ...
    oncomplete="if (#{not facesContext.validationFailed}) PF('testDialog').hide()" /> 
148
BalusC

Je viens de googler cette solution . En gros, l'idée est d'utiliser actionListener au lieu de l'action du bouton, et en sauvegardant un haricot, vous ajoutez un paramètre de rappel qui sera ensuite archivé dans la méthode oncomplete du bouton. Exemple de code partiel:

JSF en premier:

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

Haricot de sauvegarde:

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

J'espère que ça aide quelqu'un :)

16
soltysh

Utiliser l'attribut oncomplete de votre bouton de commande et un script très simple vous aidera beaucoup.

Votre boîte de dialogue et votre bouton de commande ressemblent à ceci:

<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 serait quelque chose comme ça:

<script type="text/javascript">
    function handleDialogSubmit(xhr, status, args) {
        if (args.validationFailed) {
            dialog.show();
        } else {
            dialog.hide();
        }
    }
</script>
15
Alonso Dominguez

J'utilise cette solution:

Code JSF:

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

Code de haricot de soutien:

public void saveTable() {
    RequestContext rc = RequestContext.getCurrentInstance();
    rc.execute("PF('dlgModify').hide()");
}
7
Antaeus

Je crois que c'est la solution la plus propre. En faisant cela vous vous n'avez pas besoin de changer le code de vos boutons. Cette solution remplace le prototype de la fonction de masquage.

$(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 cette façon, vous pouvez garder votre code comme:

<p:commandButton value="Save" oncomplete="videoDetalheDialogJS.hide();" 
   actionListener="#{videoBean.saveVideo(video)}" />
3
Luís Soares

La solution la plus simple est de ne pas avoir de "widget.hide", ni dans onclick, ni dans oncomplete. Supprimez les fonctions de masquage et mettez simplement

visible="#{facesContext.validationFailed}" 

pour la balise de dialogue

1
makkasi