2013-03-23 18 views
7

Ich versuche, Formularüberprüfung für ein E-Mail-Feld zu implementieren. Die Validierung sollte Folgendes tun:Email-Validierung einzeln

  • Überprüfen Sie, ob E-Mail ohne Angabe eines automatisch getan werden eingegeben wurde wurde
  • Überprüfen Sie, ob die E-Mail ein gültiges Format hat (erscheint eine Nachricht über erforderliche Attribut und angezeigt, wenn keine E-Mail eingegeben Attribut) und eine Meldung angezeigt, wenn das Format falsch ist
  • überprüfen Sie, ob die E-Mail über ein $ http.get nennen einzigartig ist und eine Meldung angezeigt, falls wurde die E-Mail gefunden und daher nicht

verwendet werden können, Ich möchte, dass die erste Nachricht erscheint, wenn das fie ld ist leer, die zweite Nachricht erscheint, wenn die E-Mail ungültig ist und die dritte Nachricht erscheint, wenn die E-Mail-Adresse gefunden wird und daher nicht einzeln nacheinander angezeigt wird.

Das funktioniert, wenn ich nur mit dem Attribut "required" versuche, aber sobald ich mein per E-Mail verfügbares Direktivenattribut hinzufüge, prüft es nicht mehr das Format der E-Mail und die E-Mail-Anweisung wird zusammen mit der E-Mail ausgeführt erforderliches Attribut Beide Nachrichten erscheinen, aber ich möchte nur, dass der Benutzer jeweils eine Nachricht sieht.

Ich benutze angularjs 1.1.3.

Kann mir jemand sagen, was ich falsch machen könnte?

HTML

<div id="user_mod" class="mod_form" ng-show="userModScreenIsVisible"> 
<form name="mod_user" novalidate> 
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" required email-available/> 
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid: 
     <span ng-show="mod_user.email.$error.required">Please enter your email.</span> 
     <span ng-show="mod_user.email.$error.email">This is not a valid email.</span> 
     <span ng-show="mod_user.email.$error.emailAvailable">This email address is already taken.</span> 
    </div> 
</form> 

Richtlinie

directive('emailAvailable', function($http) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       ctrl.$setValidity('emailAvailable', false); 
       if(viewValue !== "" && typeof viewValue !== "undefined") { 
        console.log("variable is defined"); 

        $http.get('/api/user/email/' + viewValue + '/available') 
         .success(function(data, status, headers, config) { 
          console.log(status); 
          ctrl.$setValidity('emailAvailable', true); 
          return viewValue; 
         }) 
         .error(function(data, status, headers, config) { 
          console.log("error"); 
          ctrl.$setValidity('emailAvailable', false); 
          return undefined; 
         }); 
       } else { 
        console.log("variable is undefined"); 
        ctrl.setValidity('emailAvailable', false); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}); 

Antwort

19

Ich sehe, du hast bereits ein eigenes Problem gelöst, aber ich glaube, ich kann Ihnen einige Tipps/Beratung bieten hier (ich hoffe,):

1) Alles was Sie tun mussten, um sicherzustellen, dass Ihr Validator ausgeführt wurde af ter der eingebaute Winkelprüfer war push() es auf ctrl.$parsers, anstatt unshift() es.

2) Um zu verhindern, dass Ihr Validator aufgrund der zuvor ausgeführten Validatoren ausgeführt wird, die dessen ungültigen Wert anzeigen (d. H. Wenn Sie den Ajax-Aufruf nicht ausführen möchten, wenn das Feld bereits ungültig ist). Sie müssen nur ctrl.$invalid in einer if Anweisung in Ihrem Validator überprüfen.

3) Sie möchten Ihr Formular mit einem separaten Anruf unter $setValidity() ungültig machen, bevor Sie Ihren AJAX-Anruf starten und nachdem er empfangen wurde. Auf diese Weise ist Ihr Formular ungültig, bis der AJAX zurückkehrt und sagt, ob es gültig ist oder nicht.

4) Dies ist wahrscheinlich geringfügig, aber wenn Sie nicht auch ctrl.$formatter hinzufügen, werden Werte, die anfänglich Ihrem Objekt in $ scope zugewiesen wurden, nicht validiert, bevor sie auf den Bildschirm geschrieben werden. Dies kann ein Problem darstellen, wenn Ihr Formular dynamisch über routing, ng-repeat oder ng-include mit Daten, die bereits ausgefüllt sind, dem Bildschirm hinzugefügt wird. Im Allgemeinen sollten alle Validatoren eine $ Parser-Komponente (Ansicht -> Modell) und eine $ Formatierungskomponente (Modell -> Ansicht) haben.

5) Ein Wort der Vorsicht. Die meisten Validatoren entfernen den Wert vollständig aus dem Modell, wenn es ungültig ist. Weil Sie einen asynchronen Aufruf durchführen, müssen Sie den viewValue sofort in Ihrer Parser-Funktion zurückgeben. Normalerweise gibt die Parserfunktion undefined zurück, wenn das Feld ungültig ist, wodurch verhindert wird, dass ungültige Daten in Ihrem Modell vorhanden sind.

6) Da die Validatoren einen Status haben, der in Ihrem $ error-Objekt verwaltet wird, sollten Sie ihn löschen, wenn dieser asynchrone Validator anfänglich ausgelöst wird. Siehe unten.

7) Seite Hinweis: In Ihrer Antwort habe ich festgestellt, dass Sie Werte in Ihren Ajax-Antworthandlern zurückgeben ... das wird nichts für Sie tun. Da der Aufruf asynchron ist, kehren Sie von diesem Parser immer undefiniert zurück. Aktualisiert es dein Modell? Ich wäre überrascht, wenn es so wäre.

Hier ist, wie ich Ihre ursprüngliche Richtlinie geändert haben würde, damit es funktioniert, wie Sie wahrscheinlich möchten:

app.directive('emailAvailable', function($http, $timeout) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      console.log(ctrl); 
      // push the validator on so it runs last. 
      ctrl.$parsers.push(function(viewValue) { 
       // set it to true here, otherwise it will not 
       // clear out when previous validators fail. 
       ctrl.$setValidity('emailAvailable', true); 
       if(ctrl.$valid) { 
        // set it to false here, because if we need to check 
        // the validity of the email, it's invalid until the 
        // AJAX responds. 
        ctrl.$setValidity('checkingEmail', false); 

        // now do your thing, chicken wing. 
        if(viewValue !== "" && typeof viewValue !== "undefined") { 
         $http.get('/api/user/email/' + viewValue + '/available') 
          .success(function(data, status, headers, config) { 
           ctrl.$setValidity('emailAvailable', true); 
           ctrl.$setValidity('checkingEmail', true); 
          }) 
          .error(function(data, status, headers, config) { 
           ctrl.$setValidity('emailAvailable', false); 
           ctrl.$setValidity('checkingEmail', true); 
          }); 
        } else { 
         ctrl.$setValidity('emailAvailable', false); 
         ctrl.$setValidity('checkingEmail', true); 
        } 
       } 
       return viewValue; 
      }); 

     } 
    }; 
}); 

And... of course, here is a plunker demonstrating it all

+0

Ahhhaaaaa, das erklärt eine Menge Dinge. Die Standard-Validator-Methoden befinden sich also im $ parser. Wenn ich meine Validierungsmethoden auf den Start des Arrays verschiebe, anstatt sie an das Ende des Arrays zu schieben, werden die Standardvalidierungsmethoden von meiner Methode überschrieben. Sie haben auch einige Knoten in meinem Kopf geöffnet, wie die Winkelvalidierung wirklich funktioniert. Haben Sie das tatsächlich durch Lesen der eckigen Dokumentation herausgefunden? Oder haben Sie andere Quellen? :) Danke trotzdem, deine ausführliche Erklärung und das Plunker-Beispiel haben mich zu einem noch glücklicheren angularjs-Benutzer gemacht. –

+0

Ich lese ihre [Quelle auf GitHub] (https://github.com/angular/angular.js/tree/master/src). ;) Dann war es ein Versuch und Irrtum. Ich schrieb auch einen [Blogeintrag darauf] (http://www.benlesh.com/2012/12/angular-js-custom-validation-via.html). –

+0

Zweite Blesche Antwort Ich sah, das zweite Mal war ich beeindruckt! – darethas

2

ich es gelöst, indem das gewünschte Attribut zu entfernen und eine zweite Richtlinie E-Mail-gültig genannt hinzufügen. Außerdem habe ich die setValidity-Methode in der else-Klausel der emailAvailable-Direktive entfernt.

HTML

<form name="mod_user" novalidate> 
    <input type="email" name="email" ng-model="user.email" placeholder="E-Mail" email-valid email-available/> 
    <div class="user-help" ng-show="mod_user.email.$dirty && mod_user.email.$invalid">Invalid: 
     <span ng-show="mod_user.email.$error.emailValid">Please enter a valid email address.</span> 
     <span ng-show="mod_user.email.$error.emailAvailable">This email address is already taken.</span> 
    </div> 
    <br/> 
    <button class="button" ng-click="hideUserModScreen()">Close</button> 
    <button class="button" ng-click="updateUserDetails()" ng-disabled="mod_user.$invalid" ng-show="updateUserDetailsButtonIsVisible">Update</button> 
    <button class="button" ng-click="saveUserDetails()" ng-disabled="mod_user.$invalid" ng-show="saveUserDetailsButtonIsVisible">Save</button> 
</form> 

Richtlinien

angular.module('myApp.directives', []). 
directive('appVersion', ['version', function (version) { 
    return function (scope, elm, attrs) { 
     elm.text(version); 
    }; 
}]). 

directive('emailAvailable', function($http) { // available 
    return { 
     require: 'ngModel', 
     link: function(scope, elem, attr, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       if(viewValue && viewValue.match(/[a-z0-9\-_][email protected][a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) { 
        console.log("variable is defined"); 

        $http.get('/api/user/email/' + viewValue + '/available') 
         .success(function(data, status, headers, config) { 
          console.log(status); 
          ctrl.$setValidity('emailAvailable', true); 
          return viewValue; 
         }) 
         .error(function(data, status, headers, config) { 
          console.log("error"); 
          ctrl.$setValidity('emailAvailable', false); 
          return undefined; 
         }); 
       } else { 
        console.log("variable is undefined"); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}). 

directive('emailValid', function() { 
    return { 
     require: 'ngModel', 
     link: function(scope, elm, attrs, ctrl) { 
      ctrl.$parsers.unshift(function(viewValue) { 
       if (viewValue && viewValue.match(/[a-z0-9\-_][email protected][a-z0-9\-_]+\.[a-z0-9\-_]{2,}/)) { 
        // it is valid 
        ctrl.$setValidity('emailValid', true); 
        return viewValue; 
       } else { 
        // it is invalid, return undefined (no model update) 
        ctrl.$setValidity('emailValid', false); 
        return undefined; 
       } 
      }); 
     } 
    }; 
}); 
+0

+1 für die Bereitstellung der Antwort. Warum akzeptierst du es nicht auch? – Stewie

+0

Es heißt, ich muss 2 Tage warten, bevor ich es akzeptieren kann :) –

+0

Ich habe trotzdem eine Antwort hinzugefügt. Weil, während deine Antwort funktioniert (vielleicht, sehe meine Antwort). Ich habe ein paar Mängel gesehen. –

0

I erweitert Ben Lesh ein wenig beantworten, durch einen Timeout-Zugabe so dass es nicht für jeden Tastendruck prüft

+0

Sie sollten in Javascript antworten, wenn die Frage in Javascript ist! – Endless