Skip to content

Commit

Permalink
fix(ngModel): revalidate the model when min/max expression values change
Browse files Browse the repository at this point in the history
As of this fix if the max or min value is changed via scope or by another ngModel
then it will trigger the model containing the min/max attributes to revalidate itself.

Closes angular#2404
  • Loading branch information
matsko committed Sep 3, 2014
1 parent b474c36 commit 03bb888
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 14 deletions.
19 changes: 17 additions & 2 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -1129,15 +1129,30 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
});

if (attr.min) {
var minVal;
ctrl.$validators.min = function(value) {
return ctrl.$isEmpty(value) || isUndefined(attr.min) || value >= parseFloat(attr.min);
return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
};

val = isDefined(val) && parseFloat(val, 10);
minVal = isNaN(val) ? undefined : val;
// TODO(matsko): implement validateLater to reduce number of validations
ctrl.$validate();
});
}

if (attr.max) {
var maxVal;
ctrl.$validators.max = function(value) {
return ctrl.$isEmpty(value) || isUndefined(attr.max) || value <= parseFloat(attr.max);
return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
};

attr.$observe('max', function(val) {
val = isDefined(val) && parseFloat(val, 10);
maxVal = isNaN(val) ? undefined : val;
// TODO(matsko): implement validateLater to reduce number of validations

This comment has been minimized.

Copy link
@IgorMinar

IgorMinar Sep 3, 2014

what if we instead just set the validation css classes in post-digest that way revalidating the model would become cheap?

This comment has been minimized.

Copy link
@matsko

matsko Sep 3, 2014

Author Owner

I think evalAsync would be better since if we used postDigest then the validation wouldn't happen until another digest. validateLater is only fired once if called X number of times and it only occurs after the digest is run.

ctrl.$validate();
});
}
}

Expand Down
44 changes: 32 additions & 12 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2894,18 +2894,28 @@ describe('input', function() {
expect(scope.form.alias.$error.min).toBeFalsy();
});

it('should validate even if min value changes on-the-fly', function(done) {
it('should validate even if min value changes on-the-fly', function() {
scope.min = 10;
compileInput('<input type="number" ng-model="value" name="alias" min="{{min}}" />');

changeInputValueTo('5');
changeInputValueTo('15');
expect(inputElm).toBeValid();

scope.min = 20;
scope.$digest();
expect(inputElm).toBeInvalid();

scope.min = 0;
scope.$digest(function () {
expect(inputElm).toBeValid();
done();
});
scope.min = null;
scope.$digest();
expect(inputElm).toBeValid();

scope.min = '20';
scope.$digest();
expect(inputElm).toBeInvalid();

scope.min = 'abc';
scope.$digest();
expect(inputElm).toBeValid();
});
});

Expand All @@ -2926,18 +2936,28 @@ describe('input', function() {
expect(scope.form.alias.$error.max).toBeFalsy();
});

it('should validate even if max value changes on-the-fly', function(done) {
it('should validate even if max value changes on-the-fly', function() {
scope.max = 10;
compileInput('<input type="number" ng-model="value" name="alias" max="{{max}}" />');

changeInputValueTo('5');
expect(inputElm).toBeValid();

scope.max = 0;
scope.$digest(function () {
expect(inputElm).toBeInvalid();
done();
});
scope.$digest();
expect(inputElm).toBeInvalid();

scope.max = null;
scope.$digest();
expect(inputElm).toBeValid();

scope.max = '4';
scope.$digest();
expect(inputElm).toBeInvalid();

scope.max = 'abc';
scope.$digest();
expect(inputElm).toBeValid();
});
});

Expand Down

0 comments on commit 03bb888

Please sign in to comment.