web-dev-qa-db-fra.com

Directive de validation de formulaire AngularJS pour afficher les erreurs de saisie

J'ai besoin de créer une directive de validation pour afficher automatiquement toutes les erreurs d'entrée pour chaque entrée. Cette directive de validation devrait montrer toutes les erreurs au moment actuel et la liste des erreurs devrait être mise à jour automatiquement pendant que l'utilisateur tape.

J'ai besoin de montrer toutes les erreurs d'entrée si l'entrée est sale, non vide et invalide. J'ai besoin d'ajouter toutes les erreurs dans l'élément html près de cet élément d'entrée.

Par exemple, si l'entrée est de type = "email" et ng-minlength = "5" et que l'utilisateur a tapé 'abc', je dois afficher de telles erreurs près de cette entrée: 'Email invalide; Veuillez saisir au moins 5 caractères; '

Par exemple, si l'entrée a type = "number" attr et min = "200" et min-model = "minnumber" et le modèle minnumber est défini sur "300" et que l'utilisateur a tapé "100", je dois afficher ces erreurs près de cette entrée: " Veuillez saisir le nombre minimum de 500; Doit être supérieur au nombre min. "

J'ai également besoin de mettre à jour tous les messages d'erreur pour l'entrée dans l'exemple précédent si le modèle associé (paramètre min-modèle) est mis à jour.

var app = angular.module('app', []);

app.controller('appCtrl', function ($scope) {

});

app.directive('validate', function () {
    return {
        restrict: 'A',
        require: 'ngModel', // require:  '^form',

        link: function (scope, element, attrs, ctrl) {
            console.log('======================');
            console.log(scope);
            console.log(element);
            console.log(attrs);
            console.log(ctrl);
            console.log(scope.form.$error);
            angular.forEach(scope.form.$error, function (value, key) {
                console.log('scope.form.$error = ' + key + ': ' + value);
                console.log(value);
            });

        }
    };
});


app.directive('positiveInteger', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                var INTEGER_REGEXP = /^\d+$/;
                if (INTEGER_REGEXP.test(viewValue)) { // it is valid
                    ctrl.$setValidity('positiveInteger', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('positiveInteger', false);
                    return undefined;
                }
            });
        }
    };
});


app.directive('positiveFloat', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                var FLOAT_REGEXP = /^(?:[1-9]\d*|0)?(?:\.\d+)?$/;
                if (FLOAT_REGEXP.test(viewValue)) { // it is valid
                    ctrl.$setValidity('positiveInteger', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('positiveInteger', false);
                    return undefined;
                }
            });
        }
    };
});


app.directive('minModel', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {
            ctrl.$parsers.unshift(function (viewValue) {
                if (viewValue > scope[attrs.minModel]) { // it is valid
                    ctrl.$setValidity('minModel', true);
                    return viewValue;
                } else { // it is invalid, return undefined (no model update)
                    ctrl.$setValidity('minModel', false);
                    return undefined;
                }
            });

        }
    };
});

Pouvez-vous aider à créer cette directive de validation?

Ou peut-être pouvez-vous me diriger dans la bonne direction?

Lien vers JSFiddle avec du code pour les tests .

P.S. Quelque chose de similaire est fait avec I-Utils mais leur directive ne donne pas la possibilité de définir des messages d'erreur similaires en un seul endroit.

12
webvitaly

Je veux suggérer de regarder ce post dans ce post, l'auteur explique comment atteindre vos objectifs, et vous pouvez plonger profondément dans le code. lien

exemple de ce post montrant des messages d'erreur

module = angular.module('app', []);

module.directive('showErrors', function($timeout) {
    return {
      restrict: 'A',
      require: '^form',
      link: function (scope, el, attrs, formCtrl) {
        // find the text box element, which has the 'name' attribute
        var inputEl   = el[0].querySelector("[name]");
        // convert the native text box element to an angular element
        var inputNgEl = angular.element(inputEl);
        // get the name on the text box
        var inputName = inputNgEl.attr('name');

        // only apply the has-error class after the user leaves the text box
        var blurred = false;
        inputNgEl.bind('blur', function() {
          blurred = true;
          el.toggleClass('has-error', formCtrl[inputName].$invalid);
        });

        scope.$watch(function() {
          return formCtrl[inputName].$invalid
        }, function(invalid) {
          // we only want to toggle the has-error class after the blur
          // event or if the control becomes valid
          if (!blurred && invalid) { return }
          el.toggleClass('has-error', invalid);
        });

        scope.$on('show-errors-check-validity', function() {
          el.toggleClass('has-error', formCtrl[inputName].$invalid);
        });

        scope.$on('show-errors-reset', function() {
          $timeout(function() {
            el.removeClass('has-error');
          }, 0, false);
        });
      }
    }
  });

module.controller('NewUserController', function($scope) {
  $scope.save = function() {
    $scope.$broadcast('show-errors-check-validity');

    if ($scope.userForm.$valid) {
      alert('User saved');
      $scope.reset();
    }
  };

  $scope.reset = function() {
    $scope.$broadcast('show-errors-reset');
    $scope.user = { name: '', email: '' };
  }
});
13
Narek Mamikonyan

Jetez un oeil à la ng-messagesdirective . C'est assez élégant. Exemple:

<form name="myForm">
  <input type="text" ng-model="field" name="myField" required minlength="5" />
  <div ng-messages="myForm.myField.$error">
    <div ng-message="required">You did not enter a field</div>
    <div ng-message="minlength">The value entered is too short</div>
  </div>
</form>

Vous pouvez ensuite le combiner avec n'importe quelle validation de formulaire. Placez simplement les messages d'erreur des validateurs sur l'objet $ $ elements et ils seront automatiquement rendus dans votre interface utilisateur.

11
Brad

Voici le modèle que j'ai utilisé (avec Angular 1.3):

app.directive('number', function() {
  var NUMBER_REGEXP = /^(\d+)$/;
  return {
    require: 'ngModel',
    link: function(scope, Elm, attrs, ctrl) {
      ctrl.$validators.number = function(modelValue, viewValue) {
        return NUMBER_REGEXP.test(viewValue);
      };
    }
  };
});

Ensuite, j'ai pu vérifier les erreurs dans le HTML (avec Bootstrap 3.3) en utilisant ce modèle:

<form name="form">
  <div class="form-group"
       ng-class="{'has-error': form.value.$dirty && form.value.$error.number}">
    <label for="id_value" class="control-label">Value:</label>
    <div>
      <input type="text" class="form-control" id="id_value" name="value"
             ng-model="model.number" number>
      <p class="help-block" ng-if="form.value.$error.number">Please enter a number</p>
    </div>
  </div>
</form>

Explication:

L'attribut number dans le <input name="value"> tag déclenche la directive, ce qui provoque le validateur ngModel'number' à appeler et à activer/désactiver value.$error.number.

Si value.$error.number est défini, puis le has-error la classe est appliquée au form-group pour afficher un champ de saisie rouge et le message d'aide s'affiche.

6
Brent Washburne