web-dev-qa-db-fra.com

Directive de validation de formulaire personnalisée pour comparer deux champs

Je suis un débutant angulaire et je tombe sur quelque chose dans la façon dont les directives de validation de formulaire d'angular fonctionnent.

Je sais que je peux assez facilement ajouter des directives à des champs individuels , mais j'essaie d'ajouter une validation qui comparera deux champs de formulaire (qui sont tous deux des éléments d'un modèle). 

Voici un squelette de formulaire:

<form name="edit_form" >
  <input name="min" type="number" ng-model="field.min"/>
  <input name="max" type="number" ng-model="field.max"/>
</form>

<div class="error" ng-show="edit_form.min.$dirty || edit_form.max.$dirty">
  <small class="error" ng-show="(what goes here?)">
    Min cannot exceed max
  </small>
</div>

En bref, je veux écrire une directive et l'utiliser pour afficher/cacher ce small.error si min et max ont tous les deux des valeurs mais min > max. Comment puis-je accéder aux deux champs d'une même directive? Une directive est-elle le bon outil pour ce travail?

41
asfallows

Много способов снять шкуру с кошки.

PLUNKER

app.directive('lowerThan', [
  function() {

    var link = function($scope, $element, $attrs, ctrl) {

      var validate = function(viewValue) {
        var comparisonModel = $attrs.lowerThan;

        if(!viewValue || !comparisonModel){
          // It's valid because we have nothing to compare against
          ctrl.$setValidity('lowerThan', true);
        }

        // It's valid if model is lower than the model we're comparing against
        ctrl.$setValidity('lowerThan', parseInt(viewValue, 10) < parseInt(comparisonModel, 10) );
        return viewValue;
      };

      ctrl.$parsers.unshift(validate);
      ctrl.$formatters.Push(validate);

      $attrs.$observe('lowerThan', function(comparisonModel){
        // Whenever the comparison model changes we'll re-validate
        return validate(ctrl.$viewValue);
      });

    };

    return {
      require: 'ngModel',
      link: link
    };

  }
]);

Использование:

<input name="min" type="number" ng-model="field.min" lower-than="{{field.max}}" />
<span class="error" ng-show="form.min.$error.lowerThan">
  Min cannot exceed max.
</span>
57
Stewie

Vous n'avez besoin d'aucune directive. Attribuez simplement la valeur "min" de max à min-value. Comme:

<input name="min" type="number" ng-model="field.min"/>
<input name="max" type="number" ng-model="field.max" min=" {{ field.min }}"/>

Et vous n'avez besoin d'aucune personnalisation. 
Plus: vous pouvez faire min=" {{ field.min + 1}}"

75
kamirru

Une simple comparaison vous conviendrait-elle?

<small class="error" ng-show="field.min > field.max">

Je pense qu'une directive serait exagérée si votre cas n'est que cela. Si vous ne vous sentez pas à l'aise avec la vue contenant la logique d'application, vous pouvez l'exporter dans une fonction du contrôleur:

$scope.isMinMaxInalid = function() {
    return $scope.field.min > $scope.field.max;
};

Et le modèle:

<small class="error" ng-show="isMinMaxInalid()">
5

Pour moi, au-delà d'un message de retour, j'avais besoin de définir le champ comme invalide, empêchant l'envoi. J'ai donc rassemblé quelques approches, comme l'approche @thestewie, avec une configuration de vue pour réunir une solution de comparaison de dates. J'espère pouvoir agréger les solutions qui ont été présentées.

Le code est dans _ PLUNKER

angular.module('MyApp')
    .directive('thisEarlierThan', function () {
        return {
            require: 'ngModel',
            restrict: 'A',
            link: function (scope, elem, attrs, ctrl) {
                var startDate,
                    endDate;

                scope.$watch(attrs.ngModel, function (newVal, oldVal, scope) {
                    startDate = newVal;
                    check();
                });

                scope.$watch(attrs.thisEarlierThan, function (newVal, oldVal, scope) {
                    endDate = newVal;
                    check();
                });

                var check = function () {
                    if (typeof startDate === 'undefined' || typeof endDate === 'undefined') {
                        return;
                    }

                    if (!validate(startDate)) {
                        startDate = new Date(startDate);
                        if (!validate(startDate)) {
                            return;
                        }
                    }

                    if (!validate(endDate)) {
                        endDate = new Date(endDate);
                        if (!validate(endDate)) {
                            return;
                        }
                    }

                    if (startDate < endDate) {
                        ctrl.$setValidity('thisEarlierThan', true);
                    }
                    else {
                        ctrl.$setValidity('thisEarlierThan', false);
                    }

                    return;
                };

                var validate = function (date) {
                    if (Object.prototype.toString.call(date) === '[object Date]') {
                        if (isNaN(date.getTime())) {
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                      return false;
                    }
                };
            }
        };
    })
;
2
Bernardo Loureiro

Ma version de la directive:

module.directive('greaterThan', function () {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attributes, ngModelController) {
            var otherValue;

            scope.$watch(attributes.greaterThan, function (value) {
                otherValue = value;

                ngModelController.$validate();
            });

            ngModelController.$parsers.unshift(function (viewValue) {
                ngModelController.$setValidity('greaterThan', !viewValue || !otherValue || viewValue > otherValue);

                return viewValue;
            });
        }
    };
});
2
Peter Hedberg

Vous pouvez consulter https://github.com/nelsonomuto/angular-ui-form-validation

Ceci fournit une directive préconfigurée avec une API qui expose l'étendue et ses modèles à votre fonction de validation.

Voici un exemple de votre cas d'utilisation spécifique: http://plnkr.co/edit/S0rBlS?p=preview

La syntaxe des validateurs de directives est celle indiquée dans l'exemple ci-dessous: { errorMessage: 'Cannot contain the number one', validator: function (errorMessageElement, val, attr, element, model, modelCtrl){ /** * The model and modelCtrl(scope) are exposed in the validator function * */ return /1/.test(val) !== true;
} }

0
nelsonomuto