2014-03-19 9 views
5

Ich habe ein einfaches HTML-Formular mit normaler Texteingabe. ng-minlength, ng-maxlength und ng-pattern eckig built-in form input directives sind am Eingang eingestellt.Angularjs Formularbestätigungsauftrag

Problem: ng-pattern Prüfung wird vor der Längenprüfung von ng-minlength und ng-maxlength durchgeführt.

Frage: Wie kann ich die Standard-Prüfreihenfolge ändern: d. H. Zuerst nach der Länge suchen, dann Musterprüfung anwenden?

Beispiel:

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

Aktuelles Verhalten:

  • eingeben "#" - siehe "Pattern Fehler"
  • eingeben "###" - siehe "Pattern Fehler"

Gewünschtes Verhalten:

  • eingeben "#" - siehe "Längenfehler"
  • eingeben "###" - siehe "Pattern Fehler"

FYI, bezogen jsfiddle.

Vielen Dank im Voraus.

+0

Siehe https: //github.com/angular/angular.js/pull/8267 – flup

Antwort

5

Schreiben Sie Ihre eigene Richtlinie:

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); 
     } 
    } 
}); 

Dann in Ihrem HTML, schließen Sie die App und verwenden Sie die Direktive:

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

Die Richtlinie verwendet my-minlength, my-maxlength und my- Muster für die drei Werte. Wenn die Länge fehlschlägt, wird das zuerst ausgelöst. Wenn nicht, wird das Muster als Fehler angezeigt, wenn es nicht übereinstimmt. Betrachten Sie das Umbenennen dieser Direktive, wenn Sie andere Stellen außer dem Namen als minlength, maxlength und pattern verwenden wollen. Wenn sie weggelassen werden, werden sie ignoriert.

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

0

i nur die Reihenfolge der Richtlinien geändert, Muster zuerst

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

EDIT: uuum, getestet Ihre Fiddel ohne Änderungen und zeigt die gewünschte Verhalten ... Richtlinien werden nach Priorität zusammengestellt, bbut Ich weiß nicht, wie man angulars Richtlinien Priorität legt ... sorry, sollte zuerst getestet haben

+0

Immer noch das gleiche Verhalten (siehe http://jsfiddle.net/7FLJx/). – alecxe

+0

Recht, herausgegeben ich meinen Beitrag @alecxe – nilsK

+0

aaand i falsch interpretiert Ihr Muster -.- ich heute lange genug gearbeitet * schleicht weg * – nilsK

1

Sie können die Standard-Check-Reihenfolge leider nicht ändern.

Eine Lösung besteht darin, einen benutzerdefinierten Validator zu schreiben, nicht so schwierig. Basierend auf this answer ich mit diesem Code kam (fiddle)

  1. Verbrauch: Es gibt eine Reihe von Validierungsfunktionen im Rahmen, bekommen sie auf unsere eigene Richtlinie verabschiedet "validators" als:

    <input name="name" type="text" ng-model="name" validators="nameValidators"/> 
    
  2. Eine Prüffunktion aussehen würde (zB für die minlength Einschränkung):

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

    Wichtig p oints sind: es nimmt den Wert und die ngModel als Argumente, führt den Test (hier value.length >= 3) und ruft ngModel.$setValidity() als geeignet.

  3. Die Richtlinie registriert die gegebenen Funktionen mit 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)); 
          } 
         } 
        }; 
    }); 
    

Viele Details gezwickt und verbessert werden kann, aber die Kontur funktioniert (wieder verlinken auf fiddle). Jetzt wird die Reihenfolge der Validierung explizit durch die Reihenfolge der Validatorfunktionen im nameValidators Array festgelegt.

2

ich in Winkel Code, warum dieses Verhalten gesucht. Dann in der Funktion 'textInputType', dass es die spezifische Funktion ist, die Texteingaben für die eckige 'input'-Direktive verarbeitet, fand ich dies am Ende dieser Funktion, wo wir drei Blöcke von Code sehen können.

// pattern validator 
if (pattern){ 
//validator logic 
} 

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

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

Also, egal, ob Sie die Erklärung Reihenfolge der ng- * Attribute im HTML-Eingabeelement ändern werden Sie immer gleiches Ergebnis erhalten, aber wenn Sie die Reihenfolge der Blöcke ändern, ich meine, setzen Sie die min Länge Validator Block vor Pattern Validator Block haben Sie das Ergebnis, das Sie erwarten.

Dies ist eine Lösung für Ihr Problem, aber Sie haben eine litte Änderung des Winkel Code zu machen, und ich weiß nicht, ob Sie wirklich so. Aber Sie haben eine sehr häufige Situation, in der die Reihenfolge der Deklaration von Validierungskonzepten wichtig ist, also muss etwas mehr getan werden, um damit umzugehen. Dank

1

Wenn Sie ng-Nachrichten verwenden, sollten Sie in der Lage sein, die Reihenfolge über die Reihenfolge der ng-Nachrichtenelemente zu setzen, zum Beispiel:

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

auch die Dokumentation zu diesem Thema: https://docs.angularjs.org/api/ngMessages/directive/ngMessages