Skip to content

Commit 71df063

Browse files
committed
fix(ngModel): do not reset bound date objects
Closes angular#6666
1 parent 44cf2e1 commit 71df063

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

src/ng/directive/input.js

+31-4
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
10091009
};
10101010
}
10111011

1012-
function weekParser(isoWeek) {
1012+
function weekParser(isoWeek, existingDate) {
10131013
if (isDate(isoWeek)) {
10141014
return isoWeek;
10151015
}
@@ -1022,16 +1022,33 @@ function weekParser(isoWeek) {
10221022
week = +parts[2],
10231023
firstThurs = getFirstThursdayOfYear(year),
10241024
addDays = (week - 1) * 7;
1025+
1026+
if (existingDate) {
1027+
return new Date(year, 0, firstThurs.getDate() + addDays,
1028+
existingDate.getHours(),
1029+
existingDate.getMinutes(),
1030+
existingDate.getSeconds(),
1031+
existingDate.getMilliseconds());
1032+
}
10251033
return new Date(year, 0, firstThurs.getDate() + addDays);
10261034
}
10271035
}
10281036

10291037
return NaN;
10301038
}
10311039

1040+
var DATE_METHOD_MAPPING = {
1041+
yyyy: 'FullYear',
1042+
MM: 'Month',
1043+
dd: 'Date',
1044+
HH: 'Hours',
1045+
mm: 'Minutes',
1046+
ss: 'Seconds'
1047+
};
1048+
10321049
function createDateParser(regexp, mapping) {
1033-
return function(iso) {
1034-
var parts, map;
1050+
return function(iso, date, timezone) {
1051+
var parts, map, getterPrefix;
10351052

10361053
if (isDate(iso)) {
10371054
return iso;
@@ -1050,6 +1067,16 @@ function createDateParser(regexp, mapping) {
10501067
map[mapping[index]] = +part;
10511068
}
10521069
});
1070+
if (date) {
1071+
getterPrefix = timezone === 'UTC' ? 'getUTC' : 'get';
1072+
1073+
forEach(DATE_METHOD_MAPPING, function(methodName, part) {
1074+
if (mapping.indexOf(part) === -1) {
1075+
// months are 0-indexed
1076+
map[part] = date[getterPrefix + methodName]() + (part === 'MM');
1077+
}
1078+
});
1079+
}
10531080
return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0);
10541081
}
10551082
}
@@ -1068,7 +1095,7 @@ function createDateInputType(type, regexp, parseDate, format) {
10681095
ctrl.$parsers.push(function(value) {
10691096
if (ctrl.$isEmpty(value)) return null;
10701097
if (regexp.test(value)) {
1071-
var parsedDate = parseDate(value);
1098+
var parsedDate = parseDate(value, ctrl.$modelValue, timezone);
10721099
if (timezone === 'UTC') {
10731100
parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
10741101
}

test/ng/directive/inputSpec.js

+34
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,17 @@ describe('input', function() {
20622062
expect(scope.form.alias.$error.month).toBeTruthy();
20632063
});
20642064

2065+
it('should only change the month of a bound date', function() {
2066+
compileInput('<input type="month" ng-model="value" ng-model-options="{timezone: \'UTC\'}" />');
2067+
2068+
scope.$apply(function() {
2069+
scope.value = new Date(Date.UTC(2013, 7, 1, 1, 0, 0));
2070+
});
2071+
changeInputValueTo('2013-12');
2072+
expect(+scope.value).toBe(Date.UTC(2013, 11, 1, 1, 0, 0));
2073+
expect(inputElm.val()).toBe('2013-12');
2074+
});
2075+
20652076
describe('min', function (){
20662077
beforeEach(function (){
20672078
compileInput('<input type="month" ng-model="value" name="alias" min="2013-01" />');
@@ -2124,6 +2135,18 @@ describe('input', function() {
21242135
expect(inputElm.val()).toBe('2013-W02');
21252136
});
21262137

2138+
it('should not affect the hours or minutes of a bound date', function (){
2139+
compileInput('<input type="week" ng-model="secondWeek"/>');
2140+
2141+
scope.$apply(function(){
2142+
scope.secondWeek = new Date(2013, 0, 11, 1, 0, 0);
2143+
});
2144+
2145+
changeInputValueTo('2013-W03');
2146+
2147+
expect(+scope.secondWeek).toBe(+new Date(2013, 0, 17, 1, 0, 0));
2148+
});
2149+
21272150
it('should set the model undefined if the input is an invalid week string', function () {
21282151
compileInput('<input type="week" ng-model="value"/>');
21292152

@@ -2549,6 +2572,17 @@ describe('input', function() {
25492572
expect(scope.form.alias.$error.time).toBeTruthy();
25502573
});
25512574

2575+
it('should only change hours and minute of a bound date', function() {
2576+
compileInput('<input type="time" ng-model="value"" />');
2577+
2578+
scope.$apply(function(){
2579+
scope.value = new Date(2013, 2, 3, 1, 0, 0);
2580+
});
2581+
2582+
changeInputValueTo('01:02');
2583+
expect(+scope.value).toBe(+new Date(2013, 2, 3, 1, 2, 0));
2584+
});
2585+
25522586
describe('min', function (){
25532587
beforeEach(function (){
25542588
compileInput('<input type="time" ng-model="value" name="alias" min="09:30:00" />');

0 commit comments

Comments
 (0)