Angularjs empêche la soumission de formulaire lorsque la validation d'entrée échoue

155

J'écris un formulaire de connexion simple en utilisant angularjs avec une validation d'entrée côté client pour vérifier que le nom d'utilisateur et le mot de passe ne sont pas vides et dépassent trois caractères. Voir le code ci-dessous:

<form name="loginform" novalidate ng-submit="login.submit()" class="css-form">
    <fieldset>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-user"></i></span>
            <input type="text" ng-model="login.username" name="username" required ng-minlength="3" placeholder="username" />
        </div>

        <div class="control-group input-prepend">
            <span class="add-on"><i class="icon-lock"></i></span>
            <input type="password" ng-model="login.password" name="password" required ng-minlength="3" placeholder="" />
        </div>

        <div class="control-group">
            <input class="btn" type="submit" value="Log in">
        </div>

    </fieldset>
</form>

Et le contrôleur:

var controller = function($scope) {

    $scope.login = {
        submit: function() {

            Console.info($scope.login.username + ' ' + $scope.login.password);
        }
    }

};

Le problème est que la login.submitfonction sera appelée même si l'entrée n'est pas valide. Est-il possible d'empêcher ce comportement?

En passant, je peux mentionner que j'utilise également bootstrap et requirejs.

Halse runique
la source
pouvons-nous l'utiliser sans balise form et toujours form.valid fonctionnerait sur ng-click!
Rizwan Patel le

Réponses:

329

Tu peux faire:

<form name="loginform" novalidate ng-submit="loginform.$valid && login.submit()">

Pas besoin de vérifications du contrôleur.

cyberwombat
la source
8
Cela devrait être la réponse acceptée. Pas besoin de vérifier quoi que ce soit dans le contrôleur
Howie
10
Je ne suis pas d'accord avec "pas besoin de vérifications du contrôleur". Et si des contrôles de validation supplémentaires se produisaient dans la fonction d'envoi.
SlaterCodes
6
Effectuez la validation supplémentaire dans la directive. Mettez à jour la validation avec $ setValidity.
TMB
@ b1tsh1ft Il serait préférable que l'état actuel de la validation soit toujours connu plutôt que déterminé lors de la soumission. C'est un peu le but de la validation angulaire. Vous ne pouvez pas avoir d'indication visuelle d'un état non valide lorsque l'oscilloscope ne le sait pas.
Kevin Beal
1
J'ai essayé cette approche, mais il semble qu'elle évalue les deux (c'est-à-dire qu'elle ne court-circuite pas le booléen après &&avoir essayé de transmettre la valeur dans le cadre de la soumission et confirmé que la valeur elle-même est "fausse"
Archimedes Trajano
67

Remplacez le bouton d'envoi par:

<button type="submit" ng-disabled="loginform.$invalid">Login</button>
Bijan
la source
1
Très bonne réponse. Tu gères!
Harsha.Vaswani
24
Vous pouvez toujours soumettre le formulaire si vous appuyez sur Entrée alors qu'un champ de saisie a le focus!
fabsenet
2
@Red: Voir le commentaire ci-dessus.
Andrei Rînea
Bien que la désactivation du bouton soit généralement le meilleur moyen de résoudre ce problème, ce n'est pas ce que l'OP a demandé.
downhand
1
Combiner cette technique pour fournir une rétroaction visuelle à l'utilisateur avec la réponse @Yashua pour empêcher la soumission de formulaire est parfait. Merci!
tkarls
43

Donc, la réponse suggérée de TheHippo n'a pas fonctionné pour moi, à la place j'ai fini par envoyer le formulaire en tant que paramètre à la fonction comme ceci:

<form name="loginform" novalidate ng-submit="login.submit(loginForm)" class="css-form">

Cela rend le formulaire disponible dans la méthode du contrôleur:

$scope.login = {
    submit : function(form) {
        if(form.$valid)....
    }
Halse runique
la source
J'ai eu le même problème. L'utilisation de votre méthode a fonctionné, cependant.
Panda4Man
C'est légèrement mieux que la réponse acceptée car le formulaire. $ Valid check se fait en JS et non en HTML.
cellepo
Cependant, je ne pense pas que vous ayez besoin de passer loginForm pour soumettre la fonction: je pense que $ scope.loginform devrait être disponible dans le JS (du moins c'était pour moi), vous pouvez donc remplacer form. $ Valid par $ scope.loginform . $ valide.
cellepo
13

Vos formulaires sont automatiquement placés dans $ scope en tant qu'objet. Il est accessible via$scope[formName]

Voici un exemple qui fonctionnera avec votre configuration d'origine et sans avoir à passer le formulaire lui-même en tant que paramètre dans ng-submit.

var controller = function($scope) {

    $scope.login = {
        submit: function() {
            if($scope.loginform.$invalid) return false;

        }
    }

};

Exemple de travail: http://plnkr.co/edit/BEWnrP?p=preview

davidmdem
la source
4
Comment accéderiez-vous au formulaire si vous utilisez la notation "En tant que contrôleur" au lieu de $ scope?
masimplo
@masimakopoulos: Vous pouvez simplement utiliser if(this.loginform.$invalid).. à la place, mais dans le HTML, vous devez donner le nom au formulaire <form name="ctrl.loginform" ... Et cela suppose que vous utilisez <div ng-controller="controller as ctrl"..dans votre contrôleur comme syntaxe. Merci @JoshCaroll
Bart
13

HTML:

<div class="control-group">
    <input class="btn" type="submit" value="Log in" ng-click="login.onSubmit($event)">
</div>

Dans votre contrôleur:

$scope.login = {
    onSubmit: function(event) {
        if (dataIsntValid) {
            displayErrors();
            event.preventDefault();
        }
        else {
            submitData();
        }
    }
}
TheHippo
la source
est-il vraiment nécessaire de faire la vérification dans la méthode onsubmit? Cela signifie que vous devez vérifier que l'entrée répond à tous les critères à la fois dans le balisage (via angular) et dans le code js. À mon avis, angular ne devrait pas appeler le onsubmit lorsque l'entrée est invalide. voir benlesh.com/2012/11/angular-js-form-validation.html en disant "ng-submit ne peut pas être appelé tant que le formulaire entier n'est pas $ valide"
Runar Halse
Vous pouvez également désactiver le bouton pour ne pas autoriser la soumission si le formulaire est valide. Vous pouvez également utiliser le formulaire an ng-submit. Si angular ne gère pas la validation du formulaire, alors event.preventDefault()c'est la voie à suivre, pour arrêter la soumission du formulaire.
TheHippo
@RunarHalse Il est vraiment nécessaire de faire la vérification. Je suis d'accord avec vous qu'il ne devrait pas en être ainsi. La raison pour laquelle la méthode onsubmit n'est pas appelée dans l'exemple que vous avez lié est que cet exemple n'a pas défini novalidate. Le navigateur empêche les événements de se déclencher, pas Angular. Voici son exemple w / nobalidate sur: plnkr.co/edit/R0C8XA?p=preview . Notez que le formulaire est soumis.
davidmdem
parfait exactement ce que je cherchais, un moyen de bloquer la soumission de formulaire en utilisant angular
setebos
3

Bien que ce ne soit pas une solution directe pour la question des OP, si votre formulaire se trouve dans un ng-appcontexte, mais que vous souhaitez qu'Angular l'ignore complètement, vous pouvez le faire explicitement en utilisant lengNonBindable directive:

<form ng-non-bindable>
  ...
</form>
Ian Clark
la source
2

Juste pour ajouter aux réponses ci-dessus,

J'avais 2 boutons réguliers comme indiqué ci-dessous. (Aucun type = "soumettre" n'importe où)

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>
<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

Peu importe combien j'ai essayé, appuyez sur Entrée une fois que le formulaire était valide , le bouton "Effacer le formulaire" a été appelé, effaçant tout le formulaire.

Pour contourner ce problème,

J'ai dû ajouter un bouton de soumission factice qui était désactivé et masqué. Et ce bouton factice devait être au-dessus de tous les autres boutons comme indiqué ci-dessous .

<button type="submit" ng-hide="true" ng-disabled="true">Dummy</button>

<button ng-click="clearAll();" class="btn btn-default">Clear Form</button>

<button ng-disabled="form.$invalid" ng-click="submit();"class="btn btn-primary pull-right">Submit</button>

Eh bien, mon intention n'était jamais de soumettre sur Enter, donc le hack donné ci-dessus fonctionne très bien.

vighnu
la source
vous pouvez arrêter de soumettre en appuyant sur Entrée également en supprimant l'attribut on ng-submit de votre formulaire
Kieran
1

Je sais que c'est un vieux fil mais j'ai pensé que je ferais aussi une contribution. Ma solution étant similaire au post déjà marqué comme réponse. Certaines vérifications JavaScript en ligne font l'affaire.

ng-click="form.$invalid ? alert('Please correct the form') : saveTask(task)"
Dave Russell
la source
1
Vous pouvez toujours soumettre le formulaire si vous appuyez sur Entrée alors qu'un champ de saisie a le focus!
Yevgeniy Afanasyev
0

Je sais qu'il est tard et qu'on m'a répondu, mais j'aimerais partager les trucs sympas que j'ai faits. J'ai créé une directive ng-validate qui accroche le onsubmit du formulaire, puis il émet prevent-default si le $ eval est faux:

app.directive('ngValidate', function() {
  return function(scope, element, attrs) {
    if (!element.is('form'))
        throw new Error("ng-validate must be set on a form elment!");

    element.bind("submit", function(event) {
        if (!scope.$eval(attrs.ngValidate, {'$event': event}))
            event.preventDefault();
        if (!scope.$$phase)
            scope.$digest();            
    });
  };
});

Dans votre html:

<form name="offering" method="post" action="offer" ng-validate="<boolean expression">
Ran Cohen
la source