Angular - расширение субобъекта $resource с помощью настраиваемых методов
В большинстве случаев результатом метода <custom-resource>.query()
является массив, который может быть легко расширен с помощью некоторых методов (бизнес-логик) со следующим кодом (factory):
var Data = $resource('http://..');
Data.prototype.foo = function() {return ...};
это идеально подходит для использования с ng-repeat/ng-классом, например:
<tr ng-repeat="item in responseData" ng-class="{warning: item.foo()}">..</tr>
Моя проблема заключается в том, что каждый запрос ответа инкапсулирован в объект, который, помимо фактического списка, имеет некоторые мета-свойства (сортировка информации и т.д.), поэтому последний возвращаемый объект выглядит следующим образом:
{ order_field: "name", items: [{..}, {..},{..}] }
Теперь, как мне сделать то же, что раньше, с ng-repeat/ng-class?
<tr ng-repeat="item in responseData.items" ng-class="????">..</tr>
предыдущий метод не будет работать, поскольку метод "foo" определен на responseData
и NOT на item
object
Есть ли способ напрямую расширить базовый класс, используемый для создания объектов в списке?
Спасибо!
Ответы
Ответ 1
Я нашел эту проблему раньше, и решение кажется transformResponse
, как говорит Джон Ледбеттер в другом ответе.
В любом случае , если вам нужно сохранить весь объект, а также иметь массив в "элементах", заполненный экземплярами ресурса, вы можете сделать это с помощью следующего трюка:
Взяв пример от Джона и немного изменив его:
angular.module('foo')
.factory('Post', ['$resource', function($resource) {
var Post = $resource('/api/posts/:id', { id: '@id' }, {
query: {
method: 'GET',
isArray: false, // <- not returning an array
transformResponse: function(data, header) {
var wrapped = angular.fromJson(data);
angular.forEach(wrapped.items, function(item, idx) {
wrapped.items[idx] = new Post(item); //<-- replace each item with an instance of the resource object
});
return wrapped;
}
}
});
Post.prototype.foo = function() { /* ... */ };
return Post;
}]);
Ответ 2
Если вы используете angular -resource 1.1.5 (который, насколько я могу сказать, отлично работает с angular 1.0.7), есть опция transformResponse
, которую вы можете указать при переопределении $resource
методы:
angular.module('foo')
.factory('Post', ['$resource', function($resource) {
var Post = $resource('/api/posts/:id', { id: '@id' }, {
query: {
method: 'GET',
isArray: true,
transformResponse: function(data, header) {
var wrapped = angular.fromJson(data);
return wrapped.items;
}
}
});
Post.prototype.foo = function() { /* ... */ };
return Post;
}]);
Если вы это сделаете, вам больше не придется вручную вытаскивать элементы из завернутого ответа, и каждый элемент будет экземпляром Post
, который имеет доступ к методу .foo
. Вы можете просто написать:
<tr ng-repeat="post in posts" ng-class="{warning: post.foo()}">..</tr>
Недостатком этого является то, что вы теряете доступ к любому из внешних полей вашего ответа, которые не входят в элементы. Я все еще пытаюсь найти способ сохранить эти метаданные.
Ответ 3
Это старый вопрос, но я сам столкнулся с этим вопросом. gargc решение является правильным подходом, но есть улучшения. transformResponse
принимает массив, который передается службе $http
. Вместо того, чтобы полностью заменить функцию преобразования, вы можете добавить свое преобразование к значениям по умолчанию, чтобы просто сделать необходимые вам обновления:
angular.module('foo')
.factory('Post', function ($resource, $http) {
var Post = $resource('/api/posts/:id', { id: '@id' }, {
query: {
method: 'GET',
isArray: false,
transformResponse: $http.defaults.transformResponse.concat(function(data, header) {
angular.forEach(data.items, function(item, idx) {
data.items[idx] = new Post(item);
});
return data;
})
}
});
Post.prototype.foo = function() { /* ... */ };
return Post;
});
Ответ 4
Вы можете поместить метаданные в заголовок. Я всегда размещаю данные подкачки. Таким образом, ваш запрос по-прежнему будет возвращать массив, который, я считаю, хорош. Запросы должны возвращать массивы данных, а не отдельные данные.