Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force validation to run on model when other model changes?

I have an input field with a number of $validators registered on it that updates the model. Some of these validators does comparisons to other values on the scope (which are also updated with input fields).

How do I force AngularJS to run these validations again when the other values are changed on which it is dependant?

I've tried finding anything relating to this in the documentation and also created a $watch on the dependant field and just set the model value to itself (hoping it would force a revalidation) but no luck on either counts.

like image 827
Wilhelm Kleu Avatar asked Mar 25 '15 15:03

Wilhelm Kleu


2 Answers

If you're using Angularjs 1.3+ you can use the $validate method. Lets say your input "A" is the one which depends on the others inputs, lets call them "B"s. You can add a function to each of the B's $viewChangeListeners which will just call the A's $validate method. This will have the following effect; each time you modify one of the B input, your A inputs $validators will run.

like image 103
jcz Avatar answered Nov 14 '22 22:11

jcz


I know that this was answered a while ago, but I had a similar issue and I managed to cobble a suitable solution together from a stack of other answers and a bit of trial and error. I figure someone else might look for something similar one day...

Here's a method which (as far as I can tell ) ties directly in with the validation system. This particular example creates a match validation rule, which compares two models and validates if their value is identical.

<script type="text/javascript">
angular.module( "YourModule", [] )
    .directive( "match", function() {
        return {
            require: 'ngModel',
            restrict: 'A',
            link: function( $scope, $elem, $attrs, $ctrl ) {

                // targetModel is the name of the model you want to
                // compare against.
                var targetModel = $attrs.match;

                // Add the 'match' validation method
                $ctrl.$validators.match = function( modelValue, viewValue ) {
                    valid = $scope.$eval( targetModel ) == viewValue;
                    $ctrl.$setValidity( 'match', valid );   
                    return valid ? viewValue : undefined;
                };

                // When the target model's value changes, cause this model
                // to revalidate
                $scope.$watch( targetModel, function() {
                    $ctrl.$validate();
                } );

            }
        };
    } );

Then use like this (obviously including a form, ng-app and ng-controller):

<input type="password" ng-model="password" />
<input type="password" ng-model="confirmation" match="password" />

The general idea is that when the match directive is processed, an additional function (match) is added to the $validators on the $ctrl object, which is where other validators (required field, min length, ...) seem to live. This sets up the validation on the field, but that rule is only processed when the field with the match directive is updated.

To combat this, a watch is then set up on the target model. When the value of the target model is updated, it will run the $validate() method on the original control, allowing validation to occur in either of the two fields.

like image 36
Vector Avatar answered Nov 14 '22 21:11

Vector