Angularjs dynamische ng-Mustervalidierung

84

Ich habe ein Formular, das, wenn ein Kontrollkästchen falsch ist, die Validierung einer Texteingabe unter Verwendung der Anweisung ng-require erzwingt. Wenn das Kontrollkästchen true ist, wird das Feld ausgeblendet und ng-required auf false gesetzt.

Das Problem ist, dass ich auch einen regulären Ausdruck für die Validierung am Eingang habe, der auch die Winkelanweisung ng-pattern verwendet. Das Problem, auf das ich stoße, ist, dass wenn ein Benutzer eine ungültige Telefonnummer eingibt, das Kontrollkästchen aktiviert, um diese Eingabe zu deaktivieren (und folglich keine weitere Validierung benötigt), das Formular keine Übermittlung zulässt, da es aufgrund des ng-Musters ungültig ist.

Ich habe versucht, dieses Problem zu beheben, indem ich eine ng-change-Funktion hinzugefügt habe, um das Eingabemodell auf null zu setzen. Das ng-Muster und damit das Feld sind jedoch beim ersten Satz des Kontrollkästchens immer noch auf false gesetzt. Wenn ich jedoch das Kontrollkästchen deaktiviere und alles auf das ursprüngliche Laden des Formulars zurücksetze, aktivieren Sie das Kontrollkästchen erneut. Das Formular ist gültig und kann gesendet werden. Ich bin mir nicht sicher, was mir fehlt. Hier ist der ng-change Code, den ich bisher habe:

    var phoneNumberRegex = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    $scope.phoneNumberPattern = phoneNumberRegex;
    $scope.removeValidation = function() {
        if ($scope.cell._newUser === false) {
            $scope.request._number = '';
            $scope.phoneNumberPattern = /[0-9a-zA-Z]?/;
        } else {
            $scope.phoneNumberPattern = phoneNumberRegex;
        }
    };
Brian
quelle

Antworten:

175

Dies ist ein interessantes Problem, komplexe Winkelvalidierung. Die folgende Geige implementiert, was Sie wollen:

http://jsfiddle.net/2G8gA/1/

Einzelheiten

Ich habe eine neue Direktive erstellt, rpatterndie eine Mischung aus Angulars ng-requiredund dem ng-patternCode von ist input[type=text]. Was es tut, ist das requiredAttribut des Feldes zu beobachten und dies bei der Validierung mit regulärem Ausdruck zu berücksichtigen, dh wenn es nicht erforderlich ist, markieren Sie das Feld als valid-pattern.

Anmerkungen

  • Der größte Teil des Codes stammt von Angular und ist auf diese Anforderungen zugeschnitten.
  • Wenn das Kontrollkästchen aktiviert ist, ist das Feld erforderlich.
  • Das Feld wird nicht ausgeblendet, wenn das erforderliche Kontrollkästchen falsch ist.
  • Der reguläre Ausdruck wird für die Demo vereinfacht (gültig sind 3 Ziffern).

Eine schmutzige (aber kleinere) Lösung, wenn Sie keine neue Richtlinie wollen, wäre etwa:

$scope.phoneNumberPattern = (function() {
    var regexp = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    return {
        test: function(value) {
            if( $scope.requireTel === false ) {
                return true;
            }
            return regexp.test(value);
        }
    };
})();

Und in HTML wären keine Änderungen erforderlich:

<input type="text" ng-model="..." ng-required="requireTel"
    ng-pattern="phoneNumberPattern" />

Dies bringt Angular dazu, unsere test() Methode aufzurufen , anstatt dies zu berücksichtigen.RegExp.test()required

Nikos Paraskevopoulos
quelle
2
Es würde mich sehr interessieren, was die runden Klammern um und nach der Funktion tun. Ohne sie geht es nicht
NeedHack
5
Sie rufen die Funktion direkt auf und platzieren ihren Rückgabewert effektiv in der Variablen. In Javascript ist es sehr häufig, einen äußeren Bereich nicht mit Implementierungsdetails einer bestimmten Komponente zu verschmutzen, z Modulmuster .
Nikos Paraskevopoulos
6
Die schmutzige Lösung, AngularJS einen Streich zu spielen, der auf JS '"ducktyping" basiert, ist der großartigste Code, den ich heute gesehen habe. Wirklich clevere Lösung!
Florian Loch
Vielen Dank für den großartigen Code, der aber immer noch nicht sehr klar ist. 1) Laut docs.angularjs.org/api/ng/directive/input : "Wenn der Ausdruck zu einem RegExp-Objekt ausgewertet wird, wird dieser direkt verwendet. Wenn der Ausdruck ausgewertet wird in eine Zeichenfolge, dann wird es in eine RegExp konvertiert ", aber ich nehme an, phoneNumberPattern ist ein Objekt bei der Rückkehr? Soll das ein Regxp-Objekt sein? 2) Und woher kommt in der Funktion (Wert) {} im Test speichern der Parameter "Wert"? Schätzen Sie für alle Antworten!
user2499325
1
1) Die Klausel "Wenn der Ausdruck RegExp ergibt" wird von Angular implementiert, indem überprüft wird, ob das Objekt eine testMethode hat. Aus diesem Grund geben wir ihm ein Objekt mit unserer eigenen Gewohnheit test(), das im Wesentlichen ein natives JS emuliert RegExp. 2) Das valuewird natürlich von Angular bei der Durchführung der eigentlichen Gültigkeitsprüfung übergeben.
Nikos Paraskevopoulos
25

Vielleicht können Sie Nikos 'großartiger Antwort nichts wegnehmen:

<form name="telForm">
  <input name="cb" type='checkbox' data-ng-modal='requireTel'>
  <input name="tel" type="text" ng-model="..." ng-if='requireTel' ng-pattern="phoneNumberPattern" required/>
  <button type="submit" ng-disabled="telForm.$invalid || telForm.$pristine">Submit</button>
</form>

Beachten Sie die zweite Eingabe: Wir können eine verwenden ng-if, um das Rendern und die Validierung in Formularen zu steuern. Wenn die requireTelVariable nicht gesetzt ist, wird die zweite Eingabe nicht nur ausgeblendet, sondern überhaupt nicht gerendert. Daher besteht das Formular die Validierung und die Schaltfläche wird aktiviert, und Sie erhalten das, was Sie benötigen.

kumarharsh
quelle
1
Der Vorteil ist, dass es einfach ist. Der Nachteil ist, dass alle Eingaben, die entfernt werden, wenn der ng-if-Ausdruck false ist, Text enthalten, wenn ng-if später als true ausgewertet wird. Der Einfachheit halber immer noch +1.
Brad
Ich wollte hinzufügen, wenn Sie diesen Weg gehen, stellen Sie sicher, dass Sie verstehen, dass alles innerhalb des ng-if (wenn Sie es zum Beispiel auf ein div setzen) jetzt seinen eigenen Umfang hat.
Brad
5

Verwendetes Muster:

 ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"

Verwendete Referenzdatei:

 '<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>'

Beispiel für die Eingabe:

 <input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">
Anil Singh
quelle
2

 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
<input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">

Jijo Paulose
quelle
2

Ich bin neulich darauf gestoßen.

Was ich getan habe, was einfacher zu sein scheint, ist, das Muster für eine Variable im Bereich festzulegen und in der Ansicht in ng-pattern darauf zu verweisen.

Wenn "das Kontrollkästchen deaktiviert ist", setze ich den Regex-Wert beim onChanged-Rückruf einfach auf /.*/ (falls deaktiviert). ng-Muster-Picks, die sich ändern und "OK, Ihr Wert ist in Ordnung" sagen. Das Formular ist jetzt gültig. Ich würde auch die fehlerhaften Daten vom Feld entfernen, damit Sie dort keine offensichtlich schlechte Telefonnummer haben.

Ich hatte zusätzliche Probleme mit ng-erforderlich und tat das Gleiche. Lief wie am Schnürchen.

jessewolfe
quelle
0

Legt den Fehlerschlüssel für die Musterüberprüfung fest, wenn ngModel $ viewValue nicht mit einem RegExp übereinstimmt, der durch Auswertung des im Attributwert angegebenen Winkelausdrucks gefunden wurde. Wenn der Ausdruck ein RegExp-Objekt ergibt, wird dies direkt verwendet. Wenn der Ausdruck zu einer Zeichenfolge ausgewertet wird, wird er nach dem Umschließen mit den Zeichen ^ und $ in einen RegExp konvertiert.

Es scheint, dass eine am häufigsten gewählte Antwort in dieser Frage aktualisiert werden sollte, denn wenn ich es versuche, trifft es nicht zu test Funktion und Validierung nicht angewendet, was nicht funktioniert.

Beispiel aus Angular-Dokumenten funktioniert gut für mich:

Integrierte Validatoren ändern

html

<form name="form" class="css-form" novalidate>
  <div>
   Overwritten Email:
   <input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
   <span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
   Model: {{myEmail}}
  </div>
</form>

js

var app = angular.module('form-example-modify-validators', []);

app.directive('overwriteEmail', function() {
    var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;

    return {
        require: 'ngModel',
        restrict: '',
        link: function(scope, elm, attrs, ctrl) {
            // only apply the validator if ngModel is present and Angular has added the email validator
            if (ctrl && ctrl.$validators.email) {

                // this will overwrite the default Angular email validator
                ctrl.$validators.email = function(modelValue) {
                    return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
                };
             }
         }
     };
 });

Plunker

Theodor
quelle
-1

Sie können die Website https://regex101.com/ verwenden. um Ihr eigenes spezifisches Muster für ein Land zu erstellen:

Zum Beispiel Polen:

-pattern = xxxxxxxxx OR xxx-xxx-xxx OR xxx xxx xxx 
-regexp ="^\d{9}|^\d{3}-\d{3}-\d{3}|^\d{3}\s\d{3}\s\d{3}"
Lepton
quelle