bince
bince

Reputation: 2031

How do I attach validators on an input field in angular that accesses another model in the form

I have a range input (between [lowerValue] and [upperValue]) on a form and I want to make a reusable directive called 'validateGreaterThan' that can be attached to any form and use the ngModel $validators functionality so I can attach multiple ones onto an input.

You can check a simple demo on jsbin here:

http://jsbin.com/vidaqusaco/1/

I've set up a directive called nonNegativeInteger and that works correctly, however, the validateGreaterThan directive I have isn't working. How can I get it to reference the lowerValue?

I appreciate any help with this.

Upvotes: 1

Views: 165

Answers (1)

bhantol
bhantol

Reputation: 9616

Here is the basic idea:-

Define 2 directives and let each directive refer to the other field buy passing its name. When the validator runs on the current field you can retrieve the model value of another field and now you have values from both fields and you can ensure the relation between the 2 fields.

As per my code below I have 2 fields minimumAmount and maximumAmount where the minimumAmount cannot be greater than the maximum amount and vice-versa.

<input name="minimumAmount"  type="number" class="form-control" 
             ng-model="entity.minimumAmount"
             less-than-other-field="maximumAmount" required/>

<input name="maximumAmount" type="number" 
              ng-model="entity.maximumAmount"
              greater-than-other-field="minimumAmount"
              class="form-control"/>

Here we have 2 directives lessThanOtherField and greaterThanOtherField and they both refer to other field as we pass the other field name. greater-than-other-field="minimumAmount" we are passing the other field.

 .directive('lessThanOtherField',  ['$timeout',function($timeout){
        return {
            require: 'ngModel',
            link: function (scope, elm, attrs, ctrl) {
                var xFieldValidatorName = 'lessThanOtherField';
                var form = elm.parent().controller('form');
                var otherFieldName = attrs[xFieldValidatorName];
                var formFieldWatcher = scope.$watch(function(){
                    return form[otherFieldName];
                }, function(){
                    formFieldWatcher();//destroy watcher
                    var otherFormField = form[otherFieldName];
                    var validatorFn = function (modelValue, viewValue) {
                        var otherFieldValue = otherFormField.hasOwnProperty('$viewValue') ? otherFormField.$viewValue : undefined;
                        if (angular.isUndefined(otherFieldValue)||otherFieldValue==="") {
                            return true;
                        }
                        if (+viewValue < +otherFieldValue) {
                            if (!otherFormField.$valid) {//trigger validity of other field
                                $timeout(function(){
                                    otherFormField.$validate();
                                },100);//avoid infinite loop
                            }
                            return true;
                        } else {
                            // it is invalid, return undefined (no model update)
                            //ctrl.$setValidity('lessThanOtherField', false);
                            return false;
                        }
                    };

                    ctrl.$validators[xFieldValidatorName] = validatorFn;
                });
            }
        };

    }])
    .directive('greaterThanOtherField', ['$timeout',function($timeout){
        return {
            require: 'ngModel',
            link: function (scope, elm, attrs, ctrl) {
                var xFieldValidatorName = 'greaterThanOtherField';
                var form = elm.parent().controller('form');
                var otherFieldName = attrs[xFieldValidatorName];
                var formFieldWatcher = scope.$watch(function(){
                    return form[otherFieldName];
                }, function(){
                    formFieldWatcher();//destroy watcher
                    var otherFormField = form[otherFieldName];
                    var validatorFn = function (modelValue, viewValue) {
                        var otherFieldValue = otherFormField.hasOwnProperty('$viewValue') ? otherFormField.$viewValue : undefined;
                        if (angular.isUndefined(otherFieldValue)||otherFieldValue==="") {
                            return true;
                        }
                        if (+viewValue > +otherFieldValue) {

                            if (!otherFormField.$valid) {//trigger validity of other field
                                $timeout(function(){
                                    otherFormField.$validate();
                                },100);//avoid infinite loop
                            }
                            return true;
                        } else {
                            // it is invalid, return undefined (no model update)
                            //ctrl.$setValidity('lessThanOtherField', false);
                            return false;
                        }
                    };

                    ctrl.$validators[xFieldValidatorName] = validatorFn;
                });
            }
        };

    }])

Upvotes: 1

Related Questions