Custom form validation directive to compare two fields

匿名 (未验证) 提交于 2019-12-03 02:08:02

问题:

I'm an angular newbie, and I'm stumbling over something in how angular's form validation directives work.

I know that I can fairly easily add directives to individual fields, but I'm trying to add a validation which will compare two form fields (both of which are elements of a model).

Here's a form skeleton:

<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> 

In short, I want to write a directive and use it to show/hide this small.error if min and max both have values but min > max. How can I access both fields inside one directive? Is a directive the right tool for this job?

回答1:

Many ways to skin a cat.

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     };    } ]); 

Usage:

<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> 


回答2:

You do not need any directive. Just assign the "min" value of max to min-value. Like:

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

And you do not need any customization.
More: you can do min=" {{ field.min + 1}}"



回答3:

Would a simple comparison suit you?

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

I think a directive would be an overkill if your case is just this. If you do not feel comfortable with the view containing application logic, you can export it in a function of the controller:

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

And the template:

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


回答4:

For me, beyond a feedback message, I needed define the field as invalid, preventing submit. So I gathered some approaches, like @thestewie approach, with a view configuration to gather a solution for dates comparison. I hope can aggregate the solutions that were presented.

The code is in 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;                     }                 };             }         };     }) ; 


回答5:

My version of the 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;             });         }     }; }); 


回答6:

You may take a look at https://github.com/nelsonomuto/angular-ui-form-validation

This provides a directive that is preconfigured with an api that exposes the scope and its models to your validator function.

Here is a plunker with the your specific use case: http://plnkr.co/edit/S0rBlS?p=preview

The syntax for the directives validators is as shown in the below example : { 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;
} }



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!