Skip to content

Commit

Permalink
fix(ngModel): revalidate the model when min/max expression values cha…
Browse files Browse the repository at this point in the history
…nge for date inputs

Closes angular#6755
  • Loading branch information
matsko committed Sep 3, 2014
1 parent 546ffaf commit 6160a84
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 39 deletions.
22 changes: 18 additions & 4 deletions src/ng/directive/input.js
Original file line number Diff line number Diff line change
Expand Up @@ -1082,16 +1082,30 @@ function createDateInputType(type, regexp, parseDate, format) {
return '';
});

if (attr.min) {
if (attr.min || attr.ngMin) {
var minVal;
ctrl.$validators.min = function(value) {
return ctrl.$isEmpty(value) || isUndefined(attr.min) || parseDate(value) >= parseDate(attr.min);
return ctrl.$isEmpty(value) || isUndefined(minVal) || parseDate(value) >= minVal;
};
attr.$observe('min', function(val) {
minVal = parseObservedDateValue(val);
ctrl.$validate();
});
}

if (attr.max) {
if (attr.max || attr.ngMax) {
var maxVal;
ctrl.$validators.max = function(value) {
return ctrl.$isEmpty(value) || isUndefined(attr.max) || parseDate(value) <= parseDate(attr.max);
return ctrl.$isEmpty(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
};
attr.$observe('max', function(val) {
maxVal = parseObservedDateValue(val);
ctrl.$validate();
});
}

function parseObservedDateValue(val) {
return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
}
};
}
Expand Down
172 changes: 137 additions & 35 deletions test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2063,9 +2063,12 @@ describe('input', function() {
});

describe('min', function (){
beforeEach(function (){
compileInput('<input type="month" ng-model="value" name="alias" min="2013-01" />');
});
var scope;
beforeEach(inject(function ($rootScope){
scope = $rootScope;
$rootScope.minVal = '2013-01';
compileInput('<input type="month" ng-model="value" name="alias" min="{{ minVal }}" />');
}));

it('should invalidate', function (){
changeInputValueTo('2012-12');
Expand All @@ -2080,12 +2083,27 @@ describe('input', function() {
expect(+scope.value).toBe(+new Date(2013, 6, 1));
expect(scope.form.alias.$error.min).toBeFalsy();
});

it('should revalidate when the min value changes', function (){
changeInputValueTo('2013-07');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.min).toBeFalsy();

scope.minVal = '2014-01';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.min).toBeTruthy();
});
});

describe('max', function(){
beforeEach(function (){
compileInput('<input type="month" ng-model="value" name="alias" max="2013-01" />');
});
var scope;
beforeEach(inject(function ($rootScope){
scope = $rootScope;
$rootScope.maxVal = '2013-01';
compileInput('<input type="month" ng-model="value" name="alias" max="{{ maxVal }}" />');
}));

it('should validate', function (){
changeInputValueTo('2012-03');
Expand All @@ -2100,6 +2118,18 @@ describe('input', function() {
expect(scope.value).toBeUndefined();
expect(scope.form.alias.$error.max).toBeTruthy();
});

it('should revalidate when the max value changes', function (){
changeInputValueTo('2012-07');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.max).toBeFalsy();

scope.maxVal = '2012-01';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.max).toBeTruthy();
});
});
});

Expand Down Expand Up @@ -2204,9 +2234,12 @@ describe('input', function() {
});

describe('min', function (){
beforeEach(function (){
compileInput('<input type="week" ng-model="value" name="alias" min="2013-W01" />');
});
var scope;
beforeEach(inject(function ($rootScope){
scope = $rootScope;
$rootScope.minVal = '2013-W01';
compileInput('<input type="week" ng-model="value" name="alias" min="{{ minVal }}" />');
}));

it('should invalidate', function (){
changeInputValueTo('2012-W12');
Expand All @@ -2221,12 +2254,26 @@ describe('input', function() {
expect(+scope.value).toBe(+new Date(2013, 0, 17));
expect(scope.form.alias.$error.min).toBeFalsy();
});

it('should revalidate when the min value changes', function (){
changeInputValueTo('2013-W03');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.min).toBeFalsy();

scope.minVal = '2014-W01';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.min).toBeTruthy();
});
});

describe('max', function(){
beforeEach(function (){
compileInput('<input type="week" ng-model="value" name="alias" max="2013-W01" />');
});
beforeEach(inject(function ($rootScope){
$rootScope.maxVal = '2013-W01';
scope = $rootScope;
compileInput('<input type="week" ng-model="value" name="alias" max="{{ maxVal }}" />');
}));

it('should validate', function (){
changeInputValueTo('2012-W01');
Expand All @@ -2241,6 +2288,18 @@ describe('input', function() {
expect(scope.value).toBeUndefined();
expect(scope.form.alias.$error.max).toBeTruthy();
});

it('should revalidate when the max value changes', function (){
changeInputValueTo('2012-W03');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.max).toBeFalsy();

scope.maxVal = '2012-W01';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.max).toBeTruthy();
});
});
});

Expand Down Expand Up @@ -2363,9 +2422,12 @@ describe('input', function() {
});

describe('min', function (){
beforeEach(function (){
compileInput('<input type="datetime-local" ng-model="value" name="alias" min="2000-01-01T12:30:00" />');
});
var scope;
beforeEach(inject(function ($rootScope){
$rootScope.minVal = '2000-01-01T12:30:00';
scope = $rootScope;
compileInput('<input type="datetime-local" ng-model="value" name="alias" min="{{ minVal }}" />');
}));

it('should invalidate', function (){
changeInputValueTo('1999-12-31T01:02:00');
Expand All @@ -2380,12 +2442,27 @@ describe('input', function() {
expect(+scope.value).toBe(+new Date(2000, 0, 1, 23, 2, 0));
expect(scope.form.alias.$error.min).toBeFalsy();
});

it('should revalidate when the min value changes', function (){
changeInputValueTo('2000-02-01T01:02:00');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.min).toBeFalsy();

scope.minVal = '2010-01-01T01:02:00';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.min).toBeTruthy();
});
});

describe('max', function (){
beforeEach(function (){
compileInput('<input type="datetime-local" ng-model="value" name="alias" max="2019-01-01T01:02:00" />');
});
var scope;
beforeEach(inject(function ($rootScope){
$rootScope.maxVal = '2019-01-01T01:02:00';
scope = $rootScope;
compileInput('<input type="datetime-local" ng-model="value" name="alias" max="{{ maxVal }}" />');
}));

it('should invalidate', function (){
changeInputValueTo('2019-12-31T01:02:00');
Expand All @@ -2400,6 +2477,18 @@ describe('input', function() {
expect(+scope.value).toBe(+new Date(2000, 0, 1, 1, 2, 0));
expect(scope.form.alias.$error.max).toBeFalsy();
});

it('should revalidate when the max value changes', function (){
changeInputValueTo('2000-02-01T01:02:00');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.max).toBeFalsy();

scope.maxVal = '2000-01-01T01:02:00';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.max).toBeTruthy();
});
});

it('should validate even if max value changes on-the-fly', function(done) {
Expand Down Expand Up @@ -2550,9 +2639,12 @@ describe('input', function() {
});

describe('min', function (){
beforeEach(function (){
compileInput('<input type="time" ng-model="value" name="alias" min="09:30:00" />');
});
var scope;
beforeEach(inject(function ($rootScope){
$rootScope.minVal = '09:30:00';
scope = $rootScope;
compileInput('<input type="time" ng-model="value" name="alias" min="{{ minVal }}" />');
}));

it('should invalidate', function (){
changeInputValueTo('01:02:00');
Expand All @@ -2567,6 +2659,18 @@ describe('input', function() {
expect(+scope.value).toBe(+new Date(1970, 0, 1, 23, 2, 0));
expect(scope.form.alias.$error.min).toBeFalsy();
});

it('should revalidate when the min value changes', function (){
changeInputValueTo('23:02:00');
expect(inputElm).toBeValid();
expect(scope.form.alias.$error.min).toBeFalsy();

scope.minVal = '23:55:00';
scope.$digest();

expect(inputElm).toBeInvalid();
expect(scope.form.alias.$error.min).toBeTruthy();
});
});

describe('max', function (){
Expand All @@ -2589,32 +2693,30 @@ describe('input', function() {
});
});

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

changeInputValueTo('22:34:00');
changeInputValueTo('05:34:00');
expect(inputElm).toBeInvalid();

scope.max = '12:34:00';
scope.$digest(function () {
expect(inputElm).toBeValid();
done();
});
scope.max = '06:34:00';
scope.$digest();

expect(inputElm).toBeValid();
});

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 = '08:45:00';
compileInput('<input type="time" ng-model="value" name="alias" min="{{min}}" />');

changeInputValueTo('06:15:00');
expect(inputElm).toBeInvalid();

scope.min = '13:50:00';
scope.$digest(function () {
expect(inputElm).toBeValid();
done();
});
scope.min = '05:50:00';
scope.$digest();

expect(inputElm).toBeValid();
});
});

Expand Down

0 comments on commit 6160a84

Please sign in to comment.