55 votes

AngularJS: intégration à la validation côté serveur

J'ai angulaire application qui contient un bouton de sauvegarde prises à partir de ces exemples:

<button ng-click="save" ng-disabled="form.$invalid">SAVE</button>

Cela fonctionne très bien pour la validation côté client car form.$invalid devient faux en tant qu'utilisateur résout des problèmes, mais j'ai un champ e-mail qui est définie nulle si un autre utilisateur est enregistré avec le même e-mail.

Dès que j'ai mis mon champ d'e-mail non valide, je ne peux pas soumettre le formulaire, et l'utilisateur n'a aucun moyen de corriger cette erreur de validation. Alors maintenant, je peux plus utiliser form.$invalid de désactiver mon bouton submit.

Il doit y avoir une meilleure façon

75voto

Ben Lesh Points 39290

C'est un autre cas où une coutume directive est votre ami. Vous aurez envie de créer une directive et d'injecter $http, ou, $ressource pour faire un appel vers le serveur pendant que vous êtes à la validation.

Certains pseudo-code pour la coutume de la directive:

app.directive('uniqueEmail', function($http) {
  var toId;
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elem, attr, ctrl) { 
      //when the scope changes, check the email.
      scope.$watch(attr.ngModel, function(value) {
        // if there was a previous attempt, stop it.
        if(toId) clearTimeout(toId);

        // start a new attempt with a delay to keep it from
        // getting too "chatty".
        toId = setTimeout(function(){
          // call to some API that returns { isValid: true } or { isValid: false }
          $http.get('/Is/My/EmailValid?email=' + value).success(function(data) {

              //set the validity of the field
              ctrl.$setValidity('uniqueEmail', data.isValid);
          });
        }, 200);
      })
    }
  }
});

Et voici comment vous pouvez l'utiliser dans la marque:

<input type="email" ng-model="userEmail" name="userEmail" required unique-email/>
<span ng-show="myFormName.userEmail.$error.uniqueEmail">Email is not unique.</span>

EDIT: une petite explication de ce qui se passe au-dessus.

  1. Lorsque vous mettez à jour la valeur dans l'entrée, il met à jour le $scope.userEmail
  2. La directive a un $de regarder sur le $scope.userEmail il a installé dans sa fonction de liaison.
    • Lorsque l' $watch est déclenché, il fait un appel au serveur via $http appel ajax, en passant à l'e-mail
    • Le serveur serait de vérifier l'adresse e-mail et retourner une simple réponse, comme '{ isValid: true }
    • cette réaction est utilisée pour $setValidity du contrôle.
  3. Il est dans la balise avec ng-show configuré pour n'afficher que lors de la uniqueEmail état de validité est faux.

... pour l'utilisateur, cela signifie que:

  1. Type de l'e-mail.
  2. légère pause.
  3. "L'e-mail n'est pas unique" message s'affiche "en temps réel" si l'email n'est pas unique.

EDIT2: C'est aussi de vous permettre d'utiliser le formulaire.$non valide pour désactiver votre bouton soumettre.

30voto

Paul Points 7328

J'avais besoin de ce dans quelques projets, j'ai donc créé une directive. Enfin prit un moment pour le mettre sur GitHub pour n'importe qui qui veut une goutte dans la solution.

https://github.com/webadvanced/ng-remote-validate

Caractéristiques:

  • Baisse de solution pour l'Ajax de validation de tout texte ou de saisie de mot de passe

  • Fonctionne avec Angulars construire dans la validation et la cabine sera accessible en nomformulaire.inputName.$erreur.ngRemoteValidate

  • Les gaz les demandes de serveur (par défaut 400ms) et peut être réglé avec ng-remote-throttle="550"

  • Permet HTTP définition de la méthode (par défaut POST) avec ng-remote-method="GET"

Exemple d'utilisation pour un changement de mot de passe formulaire qui oblige l'utilisateur à entrer son mot de passe actuel ainsi que le nouveau mot de passe.:

<h3>Change password</h3>
<form name="changePasswordForm">
    <label for="currentPassword">Current</label>
    <input type="password" 
           name="currentPassword" 
           placeholder="Current password" 
           ng-model="password.current" 
           ng-remote-validate="/customer/validpassword" 
           required>
    <span ng-show="changePasswordForm.currentPassword.$error.required && changePasswordForm.confirmPassword.$dirty">
        Required
    </span>
    <span ng-show="changePasswordForm.currentPassword.$error.ngRemoteValidate">
        Incorrect current password. Please enter your current account password.
    </span>

    <label for="newPassword">New</label>
    <input type="password"
           name="newPassword"
           placeholder="New password"
           ng-model="password.new"
           required>

    <label for="confirmPassword">Confirm</label>
    <input ng-disabled=""
           type="password"
           name="confirmPassword"
           placeholder="Confirm password"
           ng-model="password.confirm"
           ng-match="password.new"
           required>
    <span ng-show="changePasswordForm.confirmPassword.$error.match">
        New and confirm do not match
    </span>

    <div>
        <button type="submit" 
                ng-disabled="changePasswordForm.$invalid" 
                ng-click="changePassword(password.new, changePasswordForm);reset();">
            Change password
        </button>
    </div>
</form>

17voto

Andrej Kaurin Points 1894

J'ai créé Plunker avec une solution qui me convient parfaitement. Il utilise une directive personnalisée mais sur la totalité du formulaire et non sur un seul champ.

http://plnkr.co/edit/HnF90JOYaz47r8zaH5JY

Je ne recommanderais pas de désactiver le bouton d'envoi pour la validation du serveur.

5voto

ses Points 2924

D'accord. Au cas où quelqu'un aurait besoin d'une version fonctionnelle, c'est ici:

De doc:

  $apply() is used to enter Angular execution context from JavaScript

 (Keep in mind that in most places (controllers, services) 
 $apply has already been called for you by the directive which is handling the event.)
 

Cela m'a fait penser que nous n'avons pas besoin de: $scope.$apply(function(s) { sinon il se plaindra de $digest

 app.directive('uniqueName', function($http) {
    var toId;
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, ctrl) {
            //when the scope changes, check the name.
            scope.$watch(attr.ngModel, function(value) {
                // if there was a previous attempt, stop it.
                if(toId) clearTimeout(toId);

                // start a new attempt with a delay to keep it from
                // getting too "chatty".
                toId = setTimeout(function(){
                    // call to some API that returns { isValid: true } or { isValid: false }
                    $http.get('/rest/isUerExist/' + value).success(function(data) {

                        //set the validity of the field
                        if (data == "true") {
                            ctrl.$setValidity('uniqueName', false);
                        } else if (data == "false") {
                            ctrl.$setValidity('uniqueName', true);
                        }
                    }).error(function(data, status, headers, config) {
                        console.log("something wrong")
                    });
                }, 200);
            })
        }
    }
});
 

HTML:

 <div ng-controller="UniqueFormController">

        <form name="uniqueNameForm" novalidate ng-submit="submitForm()">

            <label name="name"></label>
            <input type="text" ng-model="name" name="name" unique-name>   <!-- 'unique-name' because of the name-convention -->

            <span ng-show="uniqueNameForm.name.$error.uniqueName">Name is not unique.</span>

            <input type="submit">
        </form>
    </div>
 

Le contrôleur pourrait ressembler à ceci:

 app.controller("UniqueFormController", function($scope) {
    $scope.name = "Bob"
})
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X