Skip to content

Commit b24f7d8

Browse files
committed
fix(datepicker): invalidate manual input value with non-existant day
Datepicker was accepting manually input values with non-existant days, like '31/02/2014', because the javascript Date object would overflow the day value and give back '03-03-2014'. This fix checks the parsed day to see if it matches the input day value, otherwise, it invalidates the input. Fix for mgcrea#816
1 parent 7dfcc82 commit b24f7d8

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

src/datepicker/test/datepicker.spec.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,26 @@ describe('datepicker', function() {
230230
expect(elm.val()).toBe((today.getMonth() + 1) + '/15/' + (today.getFullYear() + '').substr(2));
231231
});
232232

233+
it('should correctly set the model with manually typed value', function() {
234+
var elm = compileDirective('default', { selectedDate: new Date(2014, 1, 10)});
235+
angular.element(elm[0]).triggerHandler('focus');
236+
elm.val('11/30/14');
237+
angular.element(elm[0]).triggerHandler('change');
238+
scope.$digest();
239+
expect(scope.selectedDate).toEqual(new Date(2014, 10, 30));
240+
expect(angular.element(elm[0]).hasClass('ng-valid')).toBeTruthy();
241+
});
242+
243+
it('should invalidate input with non-existing manually typed value', function() {
244+
var elm = compileDirective('default', { selectedDate: new Date(2014, 1, 10)});
245+
angular.element(elm[0]).triggerHandler('focus');
246+
elm.val('02/31/14');
247+
angular.element(elm[0]).triggerHandler('change');
248+
scope.$digest();
249+
expect(scope.selectedDate).toBeUndefined();
250+
expect(angular.element(elm[0]).hasClass('ng-invalid')).toBeTruthy();
251+
});
252+
233253
it('should correctly be cleared when model is cleared', function() {
234254
var elm = compileDirective('default');
235255
scope.selectedDate = null;

src/helpers/date-parser.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ angular.module('mgcrea.ngStrap.helpers.dateParser', [])
44

55
.provider('$dateParser', function($localeProvider) {
66

7-
// define a custom ParseDate object to use instead of native Date
7+
// define a custom ParseDate object to use instead of native Date
88
// to avoid date values wrapping when setting date component values
99
function ParseDate() {
1010
this.year = 1970;
@@ -53,7 +53,7 @@ angular.module('mgcrea.ngStrap.helpers.dateParser', [])
5353
for (var i=0; i<len; i++) {
5454
if (array[i].toLowerCase() === str) { return i; }
5555
}
56-
return -1; // Return -1 per the "Array.indexOf()" method.
56+
return -1; // Return -1 per the "Array.indexOf()" method.
5757
}
5858

5959
var defaults = this.defaults = {
@@ -144,7 +144,14 @@ angular.module('mgcrea.ngStrap.helpers.dateParser', [])
144144
formatSetMap[i] && formatSetMap[i].call(date, matches[i+1]);
145145
}
146146
// convert back to native Date object
147-
return date.toDate();
147+
var newDate = date.toDate();
148+
149+
// check new native Date object for day values overflow
150+
if (parseInt(date.day, 10) !== newDate.getDate()) {
151+
return false;
152+
}
153+
154+
return newDate;
148155
};
149156

150157
$dateParser.getDateForAttribute = function(key, value) {
@@ -177,7 +184,7 @@ angular.module('mgcrea.ngStrap.helpers.dateParser', [])
177184
time = new Date(parseInt(value, 10)).setFullYear(1970, 0, 1);
178185
} else if (angular.isString(value) && 0 === value.length) { // Reset time
179186
time = key === 'minTime' ? -Infinity : +Infinity;
180-
} else {
187+
} else {
181188
time = $dateParser.parse(value, new Date(1970, 0, 1, 0));
182189
}
183190

src/helpers/test/date-parser.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ describe('dateParser', function () {
294294
{val:'20/10/2014', expect: new Date(2014,9,20), reason:'4 digit year unambiguous day/month'},
295295
{val:'10/10/2014', expect: new Date(2014,9,10), reason:'4 digit year ambiguous day/month'},
296296
{val:'10/10/1814', expect: new Date(1814,9,10), reason:'4 digit year ambiguous day/month with different century'},
297+
{val:'30/02/2014', expect: false, reason:'non-existing month day'},
297298
]);
298299
});
299300

@@ -308,6 +309,7 @@ describe('dateParser', function () {
308309
{ val: '2014/08/31', baseVal: new Date(2014,1,25), expect: false },
309310
{ val: '2014', baseVal: new Date(2014,1,25), expect: false },
310311
{ val: 'Jan', baseVal: new Date(2014,1,25), expect: false },
312+
{ val: '31/09/2014', baseVal: new Date(2014,1,25), expect: false },
311313
];
312314

313315
beforeEach(function() {
@@ -333,6 +335,7 @@ describe('dateParser', function () {
333335
{ val: '31/08/2014', baseVal: new Date(2014,1,25), expect: false },
334336
{ val: '2014', baseVal: new Date(2014,1,25), expect: false },
335337
{ val: 'Jan', baseVal: new Date(2014,1,25), expect: false },
338+
{ val: '2014/09/31', baseVal: new Date(2014,1,25), expect: false },
336339
];
337340

338341
beforeEach(function() {

0 commit comments

Comments
 (0)