Given a WebApi2 service that returns json values like this:
{
id: 1109,
effectiveDate: "2014-10-05T00:00:00", // the date is a string (newtonsoft.json)
text: "Duis et rhoncus nibh. Cras rhoncus cursus diam",
fundSource: "Test"
}
I need the date to appear in the bound angular / bootstrap / date picker correctly.
I need to transform the date into the format yyyy-mm-dd (without the time) when binding it to an input box.
Just a pointer to some documentation explaining what the correct way to serialize dates from the API to angular. I am sure that effectiveDate
should actually be a Date
object and not a string
.
<input class="form-control"
type="text"
name="effectiveDate"
ng-model="consultation.effectiveDate"
data-date-picker="yyyy-mm-dd"
placeholder="Date" />
For completness, the service returning the json values looks like this:
app.factory('Service', ['$http', '$location', '$interpolate', function ($http, $location, $interpolate) {
return {
get: function (account) {
var url = 'api/consultations/{account}';
return $http
.get(Api.format(url, { account: account }))
.then(function (response) { return response.data; });
}
};
}]);
The controller method calls it like this:
service.get($scope.urlData.account).then(function(consultations) {
$scope.consultations = consultations;
});
I ran into the exact same problem and eventually solved it by writing an Angular http interceptor
.
It parses the server's response and converts all Datetime strings with ISO/UTC format into actual JavaScript date objects.
This allows direct binding to the datepicker and solves validation issues.
Here's the client-side Angular code, consisting of a factory (the interceptor) and the config part for providing the http interceptor:
angular.module("app")
.factory('dateInterceptor', function () {
var regexIsoUtc = /^(\d{4}|\+\d{6})(?:-(\d{2}))(?:-(\d{2}))(?:T(\d{2})):(\d{2}):(\d{2})Z$/;
function matchDate(dateString) {
if (dateString.length === 20) {
return dateString.match(regexIsoUtc);
}
return false;
};
function convertDateStringsToDates(object) {
// ensure that we're processing an object
if (typeof object !== "object") {
return object;
}
for (var key in object) {
if (!object.hasOwnProperty(key)) {
continue;
}
var value = object[key];
// check for string properties with a date format
if (typeof value === "string" && matchDate(value)) {
var date = new Date(value); // create the date from the date string
object[key] = date; // we're mutating the response directly
} else if (typeof value === "object") {
convertDateStringsToDates(value); // recurse into object
}
}
return null;
}
var interceptor = {
'response': function (response) {
if (response.data) {
convertDateStringsToDates(response.data);
}
return response;
}
};
return interceptor;
})
.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push('dateInterceptor'); // intercept responses and convert date strings into real dates
}]);
On the server side I configured Newtonsoft.Json
to serialize dates using the ISO format with UTC time zone, which is the format I test against in the interceptor:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
// serialize dates into ISO format with UTC timezone
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
The interceptor is thankfully based on the code from Automatic JSON date parsing with AngularJS and AngularJS HTTP Date Interceptor Factory.