Angular-UI 当指定日期格式为 'd-M-yyyy' 且 ng-model 的字符串值为“2014-08-31T00:00:00Z”时,日期选择器处于无效状态
Angular-UI date picker is in invalid state when specified the date format as 'd-M-yyyy' and ng-model with a string value as "2014-08-31T00:00:00Z"
我从 asp.net mvc 控制器获取日期时间值作为“2014-08-31T00:00:00Z”。当我将此值绑定到我的 angular-ui 日期选择器控件时,它的状态显示为 ng-invalid ng-invalid-date.
我也从 mvc 控制器获取日期格式,所以我也在 html.
中绑定了日期格式
当我在第 1807 行调试 ui-bootstrap-tpls.js(最新版本)文件时
它总是以未定义的形式出现。我尝试了很多选择,但我无法成功。 :(
javascript does't convert angular ui datepicker date to UTC correctly
所以请给出一些想法并建议我如何解决这个问题。
感谢和问候,
N.Murali 奎师那。
我遇到了同样的问题。问题是 Angular 需要一个实际的日期对象,而不是日期的字符串表示形式。在进行了大量研究之后,我最终向 $httpProvider 添加了一个 transformReponse,它检查所有字符串对象以查看它们是否可以转换为日期,如果可以,则实际转换它们。
angular.module('test')
.config(['$httpProvider', function ($httpProvider) {
// ISO 8601 Date Pattern: YYYY-mm-ddThh:MM:ss
var dateMatchPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
var convertDates = function (obj) {
for (var key in obj) {
if (!obj.hasOwnProperty(key)) continue;
var value = obj[key];
var typeofValue = typeof (value);
if (typeofValue === 'object') {
// If it is an object, check within the object for dates.
convertDates(value);
} else if (typeofValue === 'string') {
if (dateMatchPattern.test(value)) {
obj[key] = new Date(value);
}
}
}
}
$httpProvider.defaults.transformResponse.push(function (data) {
if (typeof (data) === 'object') {
convertDates(data);
}
return data;
});
}])
我没有足够的声誉在切特的回答下发表评论,但非常感谢这个解决方案也对我有用!我不知道你的 Github 句柄是否可以在问题中标记你,但我在 Angular UI 下提交了一个 Github 问题来帮助其他人找到解决方案并希望得到 Angular UI 伙计们来研究一下。再次感谢!
这里有几点说明:
- 首先,
datepicker
指令要求 ng-model
是一个 Date
对象。这已记录在案 here。
- 其次,上面 Chet 发布(并接受)的解决方案非常笨拙,因为它需要在 HTTP 响应中接收到的每个日期字符串,如果匹配硬-,则将其转换为
Date
对象编码模式。这不灵活,也不容易测试。对于大多数人来说,这不是正确的解决方案。
如果在您的系统中,全局日期字符串转换是正确的行为,那么正确的 Angular 设计应该是创建一个为您执行此操作的服务。这导致我...
我们(Angular UI Bootstrap)提供了一种通过 dateParser
服务将日期字符串转换为 Date
对象的机制。可以看源码here。 注意:此服务名称在 0.14.0 版本中已弃用并更改为 uibDateParser
。
这是迄今为止我找到的最佳解决方案:
.directive('uibDatepickerPopup', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
return {
restrict: 'A',
priority: 1,
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
ngModel.$validators.date = function(modelValue, viewValue) {
var value = viewValue || modelValue;
if (!attr.ngRequired && !value) {
return true;
}
if (angular.isNumber(value)) {
value = new Date(value);
}
if (!value) {
return true;
} else if (angular.isDate(value) && !isNaN(value)) {
return true;
} else if (angular.isString(value)) {
var date = uibDateParser.parse(value, dateFormat);
return !isNaN(date);
} else {
return false;
}
};
}
};
});
要使用格式化日期字符串而不是 Date 对象作为 Angular Datepicker 的 ng-model,您需要创建一个包装器指令。 wrapper 指令会将您的字符串解析为 Date 对象并将其传递给日期选择器。当您 select 一个日期时,它会从日期转换回字符串。这是一个例子 (Plunker):
(function () {
'use strict';
angular
.module('myExample', ['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller('MyController', MyController)
.directive('myDatepicker', myDatepickerDirective);
MyController.$inject = ['$scope'];
function MyController ($scope) {
$scope.dateFormat = 'dd MMMM yyyy';
$scope.myDate = '30 Jun 2017';
}
myDatepickerDirective.$inject = ['uibDateParser', '$filter'];
function myDatepickerDirective (uibDateParser, $filter) {
return {
restrict: 'E',
scope: {
name: '@',
dateFormat: '@',
ngModel: '='
},
required: 'ngModel',
link: function (scope) {
var isString = angular.isString(scope.ngModel) && scope.dateFormat;
if (isString) {
scope.internalModel = uibDateParser.parse(scope.ngModel, scope.dateFormat);
} else {
scope.internalModel = scope.ngModel;
}
scope.open = function (event) {
event.preventDefault();
event.stopPropagation();
scope.isOpen = true;
};
scope.change = function () {
if (isString) {
scope.ngModel = $filter('date')(scope.internalModel, scope.dateFormat);
} else {
scope.ngModel = scope.internalModel;
}
};
},
template: [
'<div class="input-group">',
'<input type="text" readonly="true" style="background:#fff" name="{{name}}" class="form-control" uib-datepicker-popup="{{dateFormat}}" ng-model="internalModel" is-open="isOpen" ng-click="open($event)" ng-change="change()">',
'<span class="input-group-btn">',
'<button class="btn btn-default" ng-click="open($event)"> <i class="glyphicon glyphicon-calendar"></i> </button>',
'</span>',
'</div>'
].join('')
}
}
})();
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="myExample">
<div ng-controller="MyController">
<p>
Date format: {{dateFormat}}
</p>
<p>
Value: {{myDate}}
</p>
<p>
<my-datepicker ng-model="myDate" date-format="{{dateFormat}}"></my-datepicker>
</p>
</div>
</body>
</html>
只是想将我的解决方案添加到此堆栈中。
app.directive('formatDate', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
return {
restrict: 'A',
priority: 1,
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
ngModel.$validators.date = function(modelValue, viewValue) {
var value = viewValue || modelValue;
if (!attr.ngRequired && !value) {
return true;
}
if (angular.isNumber(value)) {
value = new Date(value);
}
if (!value) {
return true;
} else if (angular.isDate(value) && !isNaN(value)) {
return true;
} else if (angular.isString(value)) {
var date = new Date(value);
return !isNaN(date);
} else {
return false;
}
}
ngModel.$formatters.push(function(value) {
return new Date(value);
});
}
};
});
我通过在 directive
:
中将字符串转换为有效的 javascript 格式解决了这个问题
看这里:
我从 asp.net mvc 控制器获取日期时间值作为“2014-08-31T00:00:00Z”。当我将此值绑定到我的 angular-ui 日期选择器控件时,它的状态显示为 ng-invalid ng-invalid-date.
我也从 mvc 控制器获取日期格式,所以我也在 html.
中绑定了日期格式当我在第 1807 行调试 ui-bootstrap-tpls.js(最新版本)文件时
它总是以未定义的形式出现。我尝试了很多选择,但我无法成功。 :(
javascript does't convert angular ui datepicker date to UTC correctly
所以请给出一些想法并建议我如何解决这个问题。
感谢和问候, N.Murali 奎师那。
我遇到了同样的问题。问题是 Angular 需要一个实际的日期对象,而不是日期的字符串表示形式。在进行了大量研究之后,我最终向 $httpProvider 添加了一个 transformReponse,它检查所有字符串对象以查看它们是否可以转换为日期,如果可以,则实际转换它们。
angular.module('test')
.config(['$httpProvider', function ($httpProvider) {
// ISO 8601 Date Pattern: YYYY-mm-ddThh:MM:ss
var dateMatchPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;
var convertDates = function (obj) {
for (var key in obj) {
if (!obj.hasOwnProperty(key)) continue;
var value = obj[key];
var typeofValue = typeof (value);
if (typeofValue === 'object') {
// If it is an object, check within the object for dates.
convertDates(value);
} else if (typeofValue === 'string') {
if (dateMatchPattern.test(value)) {
obj[key] = new Date(value);
}
}
}
}
$httpProvider.defaults.transformResponse.push(function (data) {
if (typeof (data) === 'object') {
convertDates(data);
}
return data;
});
}])
我没有足够的声誉在切特的回答下发表评论,但非常感谢这个解决方案也对我有用!我不知道你的 Github 句柄是否可以在问题中标记你,但我在 Angular UI 下提交了一个 Github 问题来帮助其他人找到解决方案并希望得到 Angular UI 伙计们来研究一下。再次感谢!
这里有几点说明:
- 首先,
datepicker
指令要求ng-model
是一个Date
对象。这已记录在案 here。 - 其次,上面 Chet 发布(并接受)的解决方案非常笨拙,因为它需要在 HTTP 响应中接收到的每个日期字符串,如果匹配硬-,则将其转换为
Date
对象编码模式。这不灵活,也不容易测试。对于大多数人来说,这不是正确的解决方案。
如果在您的系统中,全局日期字符串转换是正确的行为,那么正确的 Angular 设计应该是创建一个为您执行此操作的服务。这导致我...
我们(Angular UI Bootstrap)提供了一种通过 dateParser
服务将日期字符串转换为 Date
对象的机制。可以看源码here。 注意:此服务名称在 0.14.0 版本中已弃用并更改为 uibDateParser
。
这是迄今为止我找到的最佳解决方案:
.directive('uibDatepickerPopup', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
return {
restrict: 'A',
priority: 1,
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
ngModel.$validators.date = function(modelValue, viewValue) {
var value = viewValue || modelValue;
if (!attr.ngRequired && !value) {
return true;
}
if (angular.isNumber(value)) {
value = new Date(value);
}
if (!value) {
return true;
} else if (angular.isDate(value) && !isNaN(value)) {
return true;
} else if (angular.isString(value)) {
var date = uibDateParser.parse(value, dateFormat);
return !isNaN(date);
} else {
return false;
}
};
}
};
});
要使用格式化日期字符串而不是 Date 对象作为 Angular Datepicker 的 ng-model,您需要创建一个包装器指令。 wrapper 指令会将您的字符串解析为 Date 对象并将其传递给日期选择器。当您 select 一个日期时,它会从日期转换回字符串。这是一个例子 (Plunker):
(function () {
'use strict';
angular
.module('myExample', ['ngAnimate', 'ngSanitize', 'ui.bootstrap'])
.controller('MyController', MyController)
.directive('myDatepicker', myDatepickerDirective);
MyController.$inject = ['$scope'];
function MyController ($scope) {
$scope.dateFormat = 'dd MMMM yyyy';
$scope.myDate = '30 Jun 2017';
}
myDatepickerDirective.$inject = ['uibDateParser', '$filter'];
function myDatepickerDirective (uibDateParser, $filter) {
return {
restrict: 'E',
scope: {
name: '@',
dateFormat: '@',
ngModel: '='
},
required: 'ngModel',
link: function (scope) {
var isString = angular.isString(scope.ngModel) && scope.dateFormat;
if (isString) {
scope.internalModel = uibDateParser.parse(scope.ngModel, scope.dateFormat);
} else {
scope.internalModel = scope.ngModel;
}
scope.open = function (event) {
event.preventDefault();
event.stopPropagation();
scope.isOpen = true;
};
scope.change = function () {
if (isString) {
scope.ngModel = $filter('date')(scope.internalModel, scope.dateFormat);
} else {
scope.ngModel = scope.internalModel;
}
};
},
template: [
'<div class="input-group">',
'<input type="text" readonly="true" style="background:#fff" name="{{name}}" class="form-control" uib-datepicker-popup="{{dateFormat}}" ng-model="internalModel" is-open="isOpen" ng-click="open($event)" ng-change="change()">',
'<span class="input-group-btn">',
'<button class="btn btn-default" ng-click="open($event)"> <i class="glyphicon glyphicon-calendar"></i> </button>',
'</span>',
'</div>'
].join('')
}
}
})();
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script>
<script src="example.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="myExample">
<div ng-controller="MyController">
<p>
Date format: {{dateFormat}}
</p>
<p>
Value: {{myDate}}
</p>
<p>
<my-datepicker ng-model="myDate" date-format="{{dateFormat}}"></my-datepicker>
</p>
</div>
</body>
</html>
只是想将我的解决方案添加到此堆栈中。
app.directive('formatDate', function (dateFilter, uibDateParser, uibDatepickerPopupConfig) {
return {
restrict: 'A',
priority: 1,
require: 'ngModel',
link: function (scope, element, attr, ngModel) {
var dateFormat = attr.uibDatepickerPopup || uibDatepickerPopupConfig.datepickerPopup;
ngModel.$validators.date = function(modelValue, viewValue) {
var value = viewValue || modelValue;
if (!attr.ngRequired && !value) {
return true;
}
if (angular.isNumber(value)) {
value = new Date(value);
}
if (!value) {
return true;
} else if (angular.isDate(value) && !isNaN(value)) {
return true;
} else if (angular.isString(value)) {
var date = new Date(value);
return !isNaN(date);
} else {
return false;
}
}
ngModel.$formatters.push(function(value) {
return new Date(value);
});
}
};
});
我通过在 directive
:
看这里: