mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-12 22:45:52 +08:00
fix(input): correctly handle invalid model values for input[date/time/…]
Similar to `input[number]` Angular will throw if the model value for a `input[date]` is not a `Date` object. For `Invalid Date`s (dates whose `getTime()` is `NaN`) `input[date]` will render an empty string. Closes #8949 Closes #9375
This commit is contained in:
11
docs/content/error/ngModel/datefmt.ngdoc
Normal file
11
docs/content/error/ngModel/datefmt.ngdoc
Normal file
@@ -0,0 +1,11 @@
|
||||
@ngdoc error
|
||||
@name ngModel:datefmt
|
||||
@fullName Model is not a date object
|
||||
@description
|
||||
|
||||
All date-related inputs like `<input type="date">` require the model to be a `Date` object.
|
||||
If the model is something else, this error will be thrown.
|
||||
Angular does not set validation errors on the `<input>` in this case
|
||||
as those errors are shown to the user, but the erroneous state was
|
||||
caused by incorrect application logic and not by the user.
|
||||
|
||||
@@ -1111,7 +1111,10 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
});
|
||||
|
||||
ctrl.$formatters.push(function(value) {
|
||||
if (isDate(value)) {
|
||||
if (!ctrl.$isEmpty(value)) {
|
||||
if (!isDate(value)) {
|
||||
throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
|
||||
}
|
||||
return $filter('date')(value, format, timezone);
|
||||
}
|
||||
return '';
|
||||
@@ -1138,6 +1141,11 @@ function createDateInputType(type, regexp, parseDate, format) {
|
||||
ctrl.$validate();
|
||||
});
|
||||
}
|
||||
// Override the standard $isEmpty to detect invalid dates as well
|
||||
ctrl.$isEmpty = function(value) {
|
||||
// Invalid Date: getTime() returns NaN
|
||||
return !value || (value.getTime && value.getTime() !== value.getTime());
|
||||
};
|
||||
|
||||
function parseObservedDateValue(val) {
|
||||
return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
|
||||
|
||||
@@ -2251,14 +2251,14 @@ describe('input', function() {
|
||||
|
||||
// INPUT TYPES
|
||||
describe('month', function (){
|
||||
it('should render blank if model is not a Date object', function() {
|
||||
it('should throw if model is not a Date object', function() {
|
||||
compileInput('<input type="month" ng-model="january"/>');
|
||||
|
||||
scope.$apply(function(){
|
||||
scope.january = '2013-01';
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('');
|
||||
expect(function() {
|
||||
scope.$apply(function(){
|
||||
scope.january = '2013-01';
|
||||
});
|
||||
}).toThrowMinErr('ngModel', 'datefmt', 'Expected `2013-01` to be a date');
|
||||
});
|
||||
|
||||
it('should set the view if the model is a valid Date object', function (){
|
||||
@@ -2433,14 +2433,14 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
describe('week', function (){
|
||||
it('should set render blank if model is not a Date object', function() {
|
||||
it('should throw if model is not a Date object', function() {
|
||||
compileInput('<input type="week" ng-model="secondWeek"/>');
|
||||
|
||||
scope.$apply(function(){
|
||||
scope.secondWeek = '2013-W02';
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('');
|
||||
expect(function() {
|
||||
scope.$apply(function(){
|
||||
scope.secondWeek = '2013-W02';
|
||||
});
|
||||
}).toThrowMinErr('ngModel', 'datefmt', 'Expected `2013-W02` to be a date');
|
||||
});
|
||||
|
||||
it('should set the view if the model is a valid Date object', function (){
|
||||
@@ -2615,14 +2615,14 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
describe('datetime-local', function () {
|
||||
it('should render blank if model is not a Date object', function() {
|
||||
it('should throw if model is not a Date object', function() {
|
||||
compileInput('<input type="datetime-local" ng-model="lunchtime"/>');
|
||||
|
||||
scope.$apply(function(){
|
||||
scope.lunchtime = '2013-12-16T11:30:00';
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('');
|
||||
expect(function() {
|
||||
scope.$apply(function(){
|
||||
scope.lunchtime = '2013-12-16T11:30:00';
|
||||
});
|
||||
}).toThrowMinErr('ngModel', 'datefmt', 'Expected `2013-12-16T11:30:00` to be a date');
|
||||
});
|
||||
|
||||
it('should set the view if the model if a valid Date object.', function(){
|
||||
@@ -2890,14 +2890,14 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
describe('time', function () {
|
||||
it('should render blank if model is not a Date object', function() {
|
||||
it('should throw if model is not a Date object', function() {
|
||||
compileInput('<input type="time" ng-model="lunchtime"/>');
|
||||
|
||||
scope.$apply(function(){
|
||||
scope.lunchtime = '11:30:00';
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('');
|
||||
expect(function() {
|
||||
scope.$apply(function(){
|
||||
scope.lunchtime = '11:30:00';
|
||||
});
|
||||
}).toThrowMinErr('ngModel', 'datefmt', 'Expected `11:30:00` to be a date');
|
||||
});
|
||||
|
||||
it('should set the view if the model if a valid Date object.', function(){
|
||||
@@ -3141,11 +3141,24 @@ describe('input', function() {
|
||||
});
|
||||
|
||||
describe('date', function () {
|
||||
it('should render blank if model is not a Date object.', function() {
|
||||
it('should throw if model is not a Date object.', function() {
|
||||
compileInput('<input type="date" ng-model="birthday"/>');
|
||||
|
||||
scope.$apply(function(){
|
||||
scope.birthday = '1977-10-22';
|
||||
expect(function() {
|
||||
scope.$apply(function(){
|
||||
scope.birthday = '1977-10-22';
|
||||
});
|
||||
}).toThrowMinErr('ngModel', 'datefmt', 'Expected `1977-10-22` to be a date');
|
||||
});
|
||||
|
||||
it('should set the view to empty when the model is an InvalidDate', function() {
|
||||
compileInput('<input type="date" ng-model="val"/>');
|
||||
// reset the element type to text otherwise newer browsers
|
||||
// would always set the input.value to empty for invalid dates...
|
||||
inputElm.attr('type', 'text');
|
||||
|
||||
scope.$apply(function (){
|
||||
scope.val = new Date('a');
|
||||
});
|
||||
|
||||
expect(inputElm.val()).toBe('');
|
||||
|
||||
Reference in New Issue
Block a user