Parse date string to Date object when loading Angular UI Bootstrap Datepicker
Solution 1
As this is intentional behaviour of angular-ui-bootstrap datepicker (https://github.com/angular-ui/bootstrap/issues/4690), I ended up using Angular service/factory and moment
library.
Service dateConverter
can be injected globally to intercept all HTTP requestes/responses or only in desired controllers.
Here I use Restangular
library to handle request to REST API, hence the response.plain()
method which takes only object properties, and not Restangular methods/properties.
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;
}])
;
Solution 2
you can transform String to Date in restangular transformer, something like this
RestangularConfigurer
.addElementTransformer('<RESTRESOURCENAME>', false, function (element) {
element.createDate = new Date(element.createDate);
return element;
})
Solution 3
This broke as of Angular.UI.Bootstrap v0.13.2 (8-2-2015) Downgrading to 0.13.1 works, which is where I'm stuck today.
Wesleycho says this was done intentionally https://github.com/angular-ui/bootstrap/issues/4690
I'm ready for other date pickers that support strings if anyone has a suggestion
...soon after posting this I went down a non-angular path that I'm not proud of, but it works for both HTML5 type="date" and uib-datepicker-popup. I have a regular expression that determines if a string resembles one of the two serialized date formats I've seen, and then I have a recursive javascript function to traverse a json tree and replace those strings with Date(). You would call it just before you put in $scope (or viewmodel) ...
$http.get("../api/comm/" + commId
).success(function (resp) {
fixDates(resp);
vm.comm = resp;
});
(I need not check the string length, but I figured it would spare some cpu cycles by not running the regex if the string is obviously not a date)
//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]);
};
rsobon
Updated on July 26, 2022Comments
-
rsobon almost 2 years
I'm using Angular UI Bootstrap Datepicker: https://angular-ui.github.io/bootstrap/#/datepicker
When I render form using data received from the server, there is problem with datetime fields. My input datepicker looks like this:
<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>
My server returns response datetime as JSON string:
{ ... startedAt: "2015-05-29T02:00:00+0200" }
When I assign response data to the model
$scope.item = response;
, datepicker input field is rendered correctly (correct date is selected and it's properly formatted in format I selected). The problem is that validation does not pass. I get:itemForm.startedAt.$invalid == true
I noticed that data bound to the datepicker field should be
Date
object and not string (when I select new date from the datepicker,$scope.item.startedAt
is aDate
)I managed to work around this issue and do this in the controller:
$scope.item = response; $scope.item.startedAt = new Date($scope.item.startedAt);
It works this way... But I wouldn't like to manually convert string do date every time I get a response from the server. I tried to create a directive, that I can assign to the datepicker input field so it converts the
ng-model
for me:.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; }); } } })
Well it works, because now I can see
Date
object, when I output model in my view:{{item.startedAt}}
. However still validation fails! I suspect this is some problem with me understanding how data flows between model and the view, and how UI Bootstrap hooks into it.Also when I change my directive from
$formatters.push
to$formatters.unshift
, validation works OK, but datepicker does not format my datetime (insted of nicely formattetyyyy-MM-dd
I see ISO string inside the input) -
rsobon over 8 yearswhen you are using javascript for-in loop you probable should also use hasOwnProperty()
-
Adeel Shekhani over 4 yearsAny guidance how to use it?