Angular ресурсные объекты даты
Я использую $resource для управления моими данными. Я хотел бы преобразовать даты, помещенные в объекты даты, когда я их вывожу. Это просто упрощает работу с datepicker и т.д.
Мой factory:
AppFactories.factory("Books", ['$resource' ,function($resource){
return $resource(
"/books/:id",
{id: "@id" },
{
"update": {method: "PUT", isArray: true },
"save": {method: "POST", isArray: true },
}
);
}]);
Можно ли создать функцию в factory для преобразования дат из базы данных в объект даты и наоборот, когда я отправляю/обновляю?
Было бы очень удобно интегрировать его прямо в factory, чтобы я мог его повторно использовать.
Ответы
Ответ 1
Объект action $resource
может иметь свойство с именем interceptor
, которое позволяет вам определить объект interceptor
для этого конкретного действия (как с $http-перехватчиками). Вы можете определить свойства response
и responseError
для этого перехватчика. Таким образом, вы можете определить некоторые функции синтаксического анализа даты для действий, которые предлагает ресурс:
function parseResponseDates(response) {
var data = response.data, key, value;
for (key in data) {
if (!data.hasOwnProperty(key) && // don't parse prototype or non-string props
toString.call(data[key]) !== '[object String]') continue;
value = Date.parse(data[key]); // try to parse to date
if (value !== NaN) data[key] = value;
}
return response;
}
return $resource('/books/:id', {id: '@id'},
{
'update': {
method: 'PUT',
isArray: true,
interceptor: {response: parseResponseDates}
},
....
}
);
Надеюсь, это поможет!
Ответ 2
Вместо того, чтобы делать это на каждом ресурсе, вы можете применить его к базовому $http, как описано более подробно здесь.
app.config(["$httpProvider", function ($httpProvider) {
$httpProvider.defaults.transformResponse.push(function(responseData){
convertDateStringsToDates(responseData);
return responseData;
});
}]);
Ответ 3
Я хотел использовать Angular.js ngResource ($resource
), но я также хотел, чтобы мой синтаксический анализ не мешал чему-либо еще в $http
, а действие transformResponse
представляется более подходящим, чем опция interceptor
. @jakee parseResponseDates
хорош, потому что это общая цель, но это более грубая сила, чем я хотел; Я точно знаю, какие поля могут быть датами в моих моделях, и я только хочу анализировать эти поля как даты.
В документации указано, что значение по умолчанию transformResponse
равно angular.fromJson
, но это не совсем так; он также удаляет префикс защиты JSON-защиты, )]}',\n
, перед запуском angular.fromJson
(http.js
ссылка источника). Так как $resource
не может легко отобразить каждый массив действий transformResponse
, вам необходимо вручную обрабатывать по умолчанию transformResponse
, введя $http
, а затем вызывая $http.defaults.transformResponse.concat(your_transformer)
. Решение, к которому я пришел, в контексте вашего примера будет выглядеть примерно так:
AppFactories.factory("Books", function($resource, $http) {
var raiseBook = function(book) {
// "created_at" is declared as NOT NULL in the database
book.created_at = new Date(book.created_at);
// "completed_at" is a NULL-able field
if (book.completed_at) {
book.completed_at = new Date(book.completed_at);
}
return book;
};
var raiseBooks = function(books) {
return books.map(raiseBook);
};
return $resource("/books/:id", {
id: "@id"
}, {
update: {
method: "PUT",
isArray: true,
// some_array.concat(...) creates and returns a new Array,
// without modifying the original some_array Array
transformResponse: $http.defaults.transformResponse.concat(raiseBooks),
},
save: {
method: "POST",
isArray: true,
transformResponse: $http.defaults.transformResponse.concat(raiseBooks),
},
});
});
Обратите внимание, что Date.parse(...)
возвращает Number (миллисекунды с эпохи UNIX), поэтому если это вам нужно, вам придется изменить вызовы new Date(...)
. Но поскольку исходный вопрос требует объектов даты, new Date(...)
, вероятно, вы хотите.
Ответ 4
Я принял @chbrown ответ и сделаю службу angular для использования в любой ситуации, когда нам нужно прозрачное преобразование дат в запросе/ответе ng-ресурса на лету.
Вот gist.
Пример использования:
var Session = $resource('/api/sessions/:id', {id: '@id'}, {
query: {
method: 'GET',
isArray: true,
transformResponse: dateTransformer.transformResponse.toDate(['start', 'end'])
},
update: {
method: 'PUT',
transformRequest: dateTransformer.transformRequest.toLocalIsoString(['start', 'end'])
}
});
После того, как поля Session.query() "start" и "end" в возвращаемых объектах ресурсов будут объектами JS Date.
После сеанса сервер $update() получит JSON, где объекты JS Date в полях "start" и "end"
будут просто строками в формате ISO без часовой пояс.
Поддерживаемые трансформаторы: toDate, toLocalIsoString, toZonedIsoString.
Эта служба использует time.js для синтаксического анализа и форматирования даты, поскольку родная дата JS не поддерживает
даты без часовой пояс (они всегда анализируются как UTC + 0).
Также Lodash используется для манипуляций с объектами.