Angularjs forme un ordre de validation

J'ai un formulaire html simple contenant une entrée de texte régulière. ng-minlength , ng-maxlength et ng-pattern angular built-in forme entrée directives sont définies sur l'entrée.

Problème: ng-pattern vérification de ng-pattern est appliquée avant la vérification de longueur par ng-minlength et ng-maxlength .

Question: comment puis-je modifier l'ordre de contrôle par défaut: c.-à-d. La première vérification de la longueur, puis appliquer la vérification du modèle?

Exemple:

 <body ng-app> <div> <form name="myForm"> Name: <input name="name" type="text" ng-model="name" ng-minlength="3" ng-maxlength="16" ng-pattern="/^\w+$/"/> <div ng-show="myForm.name.$dirty && myForm.name.$invalid"> <span ng-show="myForm.name.$error.pattern">Pattern error</span> <span ng-show="myForm.name.$error.minlength || myForm.name.$error.maxlength">Length error</span> </div> <br/> <input type="submit" value="Submit"> </form> </div> </body> 

Comportement actuel:

  • Entre "#" – voir "Erreur de motif"
  • Entre "###" – voir "Erreur de motif"

Comportement souhaité:

  • Entre "#" – voir "Erreur de longueur"
  • Entre "###" – voir "Erreur de motif"

FYI, jsfiddle associé .

Merci d'avance.

Écrivez votre propre directive:

 var mod = angular.module("myApp", []); mod.directive("nameValidation", function () { return { restrict: "A", require: "ngModel", link: function (scope, element, attrs, ngModelCtrl) { var validate = function (value) { var minLen = parseInt(attrs.myMinlength, 10), maxLen = parseInt(attrs.myMaxlength, 10), pattern = attrs.myPattern, match = pattern.match(/^\/(.*)\/([gim]*)$/), lenErr = false; if (match) { pattern = new RegExp(match[1], match[2]); } if (!ngModelCtrl.$isEmpty(value)) { ngModelCtrl.$setValidity("pattern", true); if ((minLen && value.length < minLen) || (maxLen && value.length > maxLen)) { ngModelCtrl.$setValidity("length", false); lenErr = true; } else { ngModelCtrl.$setValidity("length", true); lenErr = false; } if (!lenErr) { if (match && !pattern.test(value)) { ngModelCtrl.$setValidity("pattern", false); } else { ngModelCtrl.$setValidity("pattern", true); } } } else { ngModelCtrl.$setValidity("length", true); ngModelCtrl.$setValidity("pattern", true); } } ngModelCtrl.$parsers.push(validate); ngModelCtrl.$formatters.push(validate); } } }); 

Ensuite, dans votre HTML, incluez l'application et utilisez la directive:

 <body ng-app="myApp"> <div> <form name="myForm"> Name: <input name="name" type="text" ng-model="name" name-validation="" my-minlength="3" my-maxlength="16" my-pattern="/^\w+$/"/> <div ng-show="myForm.name.$dirty && myForm.name.$invalid"> <span ng-show="myForm.name.$error.pattern">Pattern error</span> <span ng-show="myForm.name.$error.length">Length error</span> </div> <br/> <input type="submit" value="Submit"> </form> </div> </body> 

La directive utilise my-minlength, my-maxlength et my-pattern pour les trois valeurs. Si la longueur échoue, celle-ci débutera d'abord. Si ce n'est pas le cas, le motif apparaîtra comme une erreur s'il ne correspond pas. Envisagez de renommer cette directive si vous souhaitez l'utiliser, d'autres endroits, en plus du nom en tant que minlength, maxlength, et pattern peuvent être transmis par les attributs. Si elles sont laissées, elles seront ignorées.

Voir jsfiddle: http://jsfiddle.net/4zpxk/6/

J'ai cherché dans le code angulaire pourquoi ce comportement. Ensuite, dans la fonction 'textInputType', c'est la fonction spécifique qui gère les entrées de texte pour la directive 'entrée' angulaire, j'ai trouvé ceci à la fin de cette fonction, où nous pouvons voir trois blocs de code.

 // pattern validator if (pattern){ //validator logic } // min length validator if (attr.ngMinlength) { //validator logic } // max length validator if (attr.ngMaxlength) { //validator logic } 

Donc, peu importe si vous modifiez l'ordre de déclaration de vos attributs ng- * dans l'élément d'entrée html, vous obtiendrez toujours le même résultat, mais si vous modifiez l'ordre des blocs, je veux dire, placez le bloc de validateur de longueur minime avant le bloc de validateur de modèle Vous aurez le résultat que vous attendez.

C'est une solution pour votre problème, mais vous devez faire un petit changement dans le code angulaire et je ne sais pas si vous aimez vraiment cela. Mais vous avez une situation très commune où l'ordre de la déclaration des concepts de validation est important, donc il faut faire plus pour faire face à cela. Merci

Vous ne pouvez pas modifier l'ordre de contrôle par défaut malheureusement.

Une solution consiste à écrire un validateur personnalisé, pas si difficile. Sur la base de cette réponse , je suis venu avec ce code ( violon )

  1. Utilisation: il existe un éventail de fonctions de validation dans la portée, elles sont passées à notre directive personnalisée "validators" comme "validators" :

     <input name="name" type="text" ng-model="name" validators="nameValidators"/> 
  2. Une fonction de validateur ressemblerait (p. Ex. Pour la contrainte minlength ):

     function minlength(value, ngModel) { if( value == null || value == "" || value.length >= 3 ) { ngModel.$setValidity('minlength', true); return value; } else { ngModel.$setValidity('minlength', false); return; } } 

    Les points importants sont: il prend la valeur et ngModel comme arguments, effectue le test (ici value.length >= 3 ) et appelle ngModel.$setValidity() selon le cas.

  3. La directive enregistre les fonctions données avec ngModel.$parsers :

     app.directive("validators", function($parse) { return { restrict: "A", require: "ngModel", link: function(scope, el, attrs, ngModel) { var getter = $parse(attrs.validators), validators = getter(scope), i; for( i=0; i < validators.length; i++ ) { ngModel.$parsers.push((function(index) { return function(value) { return validators[index](value, ngModel); }; })(i)); } } }; }); 

De nombreux détails peuvent être modifiés et améliorés, mais le contour fonctionne (encore une fois, le lien avec le violon ). Maintenant, l'ordre de validation est explicitement défini par l'ordre des fonctions du validateur dans le tableau nameValidators .

Si vous utilisez ng-messages, vous devriez pouvoir passer la commande par l'ordre des éléments du message ng, par exemple:

 <div ng-messages="field.$error"> <ul class="validation-errors"> <li ng-message="required">This has the highest prio</li> <li ng-message="min">Second in command</li> <li ng-message="max">I'm last</li> </ul> </div> 

Aussi, documentez-vous sur ceci: https://docs.angularjs.org/api/ngMessages/directive/ngMessages

Je viens de changer l'ordre de vos directives, le modèle d'abord

 <input name="name" type="text" ng-model="name" ng-pattern="/^\w+$/" ng-minlength="3" ng-maxlength="16"/> 

EDIT : uuum, testé votre fiddel sans modification et montre le comportement souhaité … les directives sont compilées par priorité, mais je ne sais pas comment définir la priorité des directives angulaires … désolé, j'aurais dû tester cela d'abord