Désactiver le bouton d'envoi lorsque le formulaire n'est pas valide avec AngularJS

174

J'ai ma forme comme ceci:

<form name="myForm">
    <input name="myText" type="text" ng-model="mytext" required />
    <button disabled="{{ myForm.$invalid }}">Save</button>
</form>

Comme vous pouvez le voir, le bouton est désactivé si l'entrée est vide, mais il ne redevient pas activé lorsqu'il contient du texte. Comment puis-je le faire fonctionner?

Ali
la source

Réponses:

339

Vous devez utiliser le nom de votre formulaire, ainsi que ng-disabled: voici une démo sur Plunker

<form name="myForm">
    <input name="myText" type="text" ng-model="mytext" required />
    <button ng-disabled="myForm.$invalid">Save</button>
</form>
Ben Lesh
la source
Désolé, je l'utilise maintenant. Pourtant, il est toujours désactivé même lorsque la zone de texte contient du texte
ali
1
+1 Par coïncidence, je lisais juste votre excellent article: benlesh.com/2012/11/angular-js-form-validation.html
Ben
et si je n'ai pas de formulaire? Puis-je faire cela aussi sur l'élément div?
VsMaX
1
@MichaelCwienczek techniquement, vous pouvez ajouter ng-forme à une balise div: <div ng-form="myForm"> ... stuff here .. </div>. Bien que, si vous soumettez une valeur à partir d'entrées, en appuyant sur un bouton, je recommande fortement d' utiliser une <form/>balise, si pour aucune autre raison que cela permet à un utilisateur d' appuyer sur [ENTRÉE] et d'envoyer le formulaire. Mais cela constitue aussi probablement une meilleure pratique en raison d'éléments tels que des problèmes d'accessibilité.
Ben Lesh
2
@BenLesh, que faire si le bouton d'envoi n'est pas dans mon formulaire et que je dois toujours le désactiver si le formulaire n'est pas valide.
Green Wizard
33

Pour ajouter à cette réponse. Je viens de découvrir qu'il se décomposera également si vous utilisez un trait d'union dans votre nom de formulaire (Angular 1.3):

Donc, cela ne fonctionnera pas :

<form name="my-form">
    <input name="myText" type="text" ng-model="mytext" required />
    <button ng-disabled="my-form.$invalid">Save</button>
</form>
wvdz
la source
3
Oui, le nom du formulaire doit être en cas de chameau pour toutes les validations de formulaire AngularJS.
dubilla
7
en règle générale, toutes les expressions comme js reconnaîtront les objets sous la forme camelcase, tandis que le tiret est pour la syntaxe html
ecoologic
Alors, que se passe-t-il si le formulaire est membre d'un formset, et doit donc avoir un nom avec un trait d'union (comme "my_formset_name-0")?
trubliphone
2
Dans l'exemple ci-dessus, je pense que cela myForm.$invaliddevrait toujours fonctionner, donc dans votre cas, je pense que cela my_formset_name0.$invaliddevrait fonctionner.
wvdz
29

La réponse sélectionnée est correcte, mais quelqu'un comme moi peut avoir des problèmes avec la validation asynchrone avec l'envoi de la demande au côté serveur - le bouton ne sera pas désactivé pendant le traitement de la demande, donc le bouton clignotera, ce qui semble assez étrange pour les utilisateurs.

Pour annuler cela, il vous suffit de gérer $ état en attente du formulaire:

<form name="myForm">
  <input name="myText" type="text" ng-model="mytext" required />
  <button ng-disabled="myForm.$invalid || myForm.$pending">Save</button>
</form>
Ivan Sokalskiy
la source
Merci beaucoup pour la solution de validation asynchrone!
Martin Brandl
Vous devez simplement utiliser !myForm.$validqui gère également les problèmes asynchrones en attente. itnext.io/valid-and-invalid-in-angular-forms-61cfa3f2a0cd
SavageCore
6

Si vous utilisez des formulaires réactifs, vous pouvez utiliser ceci:

<button [disabled]="!contactForm.valid" type="submit" class="btn btn-lg btn primary" (click)="printSomething()">Submit</button>
Nelul
la source
2
Bien que ce soit un conseil valable pour "Angular", cette réponse n'est pas valide pour "AngularJS". À savoir, (click)et [disabled]ne sont pas du code AngularJS valide, et les formulaires réactifs ne font pas partie du framework AngularJS. "Angular est le nom de l'Angular d'aujourd'hui et de demain. AngularJS est le nom de toutes les versions v1.x d'Angular" angular.io/guide/ajs-quick-reference
dapperdan1985
1

Nous pouvons créer une directive simple et désactiver le bouton jusqu'à ce que tous les champs obligatoires soient remplis.

angular.module('sampleapp').directive('disableBtn',
function() {
 return {
  restrict : 'A',
  link : function(scope, element, attrs) {
   var $el = $(element);
   var submitBtn = $el.find('button[type="submit"]');
   var _name = attrs.name;
   scope.$watch(_name + '.$valid', function(val) {
    if (val) {
     submitBtn.removeAttr('disabled');
    } else {
     submitBtn.attr('disabled', 'disabled');
    }
   });
  }
 };
}
);

Pour plus d'informations, cliquez ici

Prashobh
la source
Votre méthode de solution fonctionne pour moi avec peu d'ajustement. Merci
Tatipaka
Pourquoi feriez-vous cela alors qu'il y a des directives natives ng-disableddans angular 1.x et [disabled]angular 2 | 4.x qui sont bien mieux testées que cela ?. Deuxièmement, pourquoi avoir une directive qui est étendue à un formulaire pour désactiver un bouton imbriqué, c'est super spécifique. Une solution mal pensée IMO.
David Barker
Ci-dessus se trouve un exemple de directive, l'original contient de nombreux scénarios tels que des cases à cocher imbriquées, etc.
Prashobh
1

<form name="myForm">
        <input name="myText" type="text" ng-model="mytext" required/>
        <button ng-disabled="myForm.$pristine|| myForm.$invalid">Save</button>
</form>

Si vous voulez être un peu plus strict

Cengkuru Michael
la source