我正在使用Angular UI Bootstrap Datepicker: https://angular-ui.github.io/bootstrap/#/datepicker
当我使用从服务器收到的数据呈现表单时,datetime字段存在问题。我的输入日期选择器如下所示:
<form name="itemForm">
<input type="datetime" class="form-control" id="startedAt" name="startedAt"
ng-model="item.startedAt"
ng-click="open($event, 'startedAt')"
uib-datepicker-popup="yyyy-MM-dd"
is-open="datepickers.startedAt"
/>
</form>
我的服务器将响应日期时间返回为JSON字符串:
{
...
startedAt: "2015-05-29T02:00:00+0200"
}
当我将响应数据分配给模型$scope.item = response;
时,正确呈现了datepicker输入字段(选择了正确的日期,并且它以我选择的格式正确格式化)。问题是验证没有通过。我明白了:
itemForm.startedAt.$invalid == true
我注意到绑定到datepicker字段的数据应该是Date
对象而不是字符串(当我从datepicker中选择新日期时,$scope.item.startedAt
是Date
)
我设法解决了这个问题并在控制器中执行此操作:
$scope.item = response;
$scope.item.startedAt = new Date($scope.item.startedAt);
它以这种方式工作......但是每次我从服务器获得响应时,我都不想手动转换字符串do日期。我尝试创建一个指令,我可以将其指定给datepicker输入字段,以便为我转换ng-model
:
.directive("asDate", function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, modelCtrl) {
modelCtrl.$formatters.push(function (input) {
var transformedInput = new Date(input);
if (transformedInput != input) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
}
})
它确实有效,因为现在我可以看到Date
对象,当我在视图中输出模型时:{{item.startedAt}}
。但仍然验证失败!我怀疑这是一个问题,我理解数据如何在模型和视图之间流动,以及UI Bootstrap如何挂钩它。
当我将指令从$formatters.push
更改为$formatters.unshift
时,验证工作正常,但是datepicker没有格式化我的日期时间(格式很好的格式yyyy-MM-dd
我看到输入中的ISO字符串)
答案 0 :(得分:1)
由于这是angular-ui-bootstrap datepicker(https://github.com/angular-ui/bootstrap/issues/4690)的故意行为,我最终使用了Angular服务/工厂和moment
库。
可以全局注入服务dateConverter
以拦截所有HTTP请求/响应,或仅在所需的控制器中。
这里我使用Restangular
库来处理对REST API的请求,因此response.plain()
方法只接受对象属性,而不是Restangular方法/属性。
var Services = angular.module('app.Services', []);
Services
.factory('dateConverter', ['dateFilter', function (dateFilter) {
var dateConverter = {};
dateConverter.prepareResponse = function (response) {
for(prop in response.plain()) {
if (response.hasOwnProperty(prop)) {
if(moment(response[prop], moment.ISO_8601, true).isValid()) {
response[prop] = new Date(response[prop]);
}
}
}
return response;
};
dateConverter.prepareRequest = function (item) {
for(prop in item.plain()) {
if (item.hasOwnProperty(prop)) {
if(angular.isDate(item[prop])){
item[prop] = dateFilter(item[prop] , "yyyy-MM-ddTHH:mm:ssZ")
}
}
}
return item;
};
return dateConverter;
}])
;
答案 1 :(得分:0)
这打破了Angular.UI.Bootstrap v0.13.2(8-2-2015) 降级到0.13.1,这就是我今天被困住的地方。
Wesleycho说这是故意的 https://github.com/angular-ui/bootstrap/issues/4690如果有人有建议,我已经准备好支持字符串的其他日期选择器了
...发布后不久我就走了一条我并不自豪的非角度路径,但它适用于HTML5 type =“date”和uib-datepicker-popup。我有一个正则表达式,确定一个字符串是否类似于我见过的两种序列化日期格式之一,然后我有一个递归的javascript函数来遍历一个json树并用Date()替换这些字符串。您可以在放入$ scope(或viewmodel)之前调用它...
$http.get("../api/comm/" + commId
).success(function (resp) {
fixDates(resp);
vm.comm = resp;
});
(我不需要检查字符串长度,但我认为如果字符串显然不是日期,则不运行正则表达式会节省一些cpu周期)
//2015-10-01T00:00:00-04:00
//2015-11-20T18:15:56.6229516-05:00
var isDate = new RegExp("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{7})?-\\d{2}:00");
function fixDates(json) {
for (i in json)
if (typeof (json[i]) == "object")
fixDates(json[i]);
else if (typeof (json[i]) == "string" && (json[i].length == 25 || json[i].length == 33) && isDate.test(json[i]))
json[i] = new Date(json[i]);
};
答案 2 :(得分:0)
你可以在restangular变换器中将String转换为Date,就像这样
RestangularConfigurer
.addElementTransformer('<RESTRESOURCENAME>', false, function (element) {
element.createDate = new Date(element.createDate);
return element;
})