Angular - расширение подобъекта $resource с помощью пользовательских методов
В большинстве случаев результат <custom-resource>.query()
Метод - это массив, который можно легко расширить с помощью некоторых методов (бизнес-логики) со следующим (фабричным) кодом:
var Data = $resource('http://..');
Data.prototype.foo = function() {return ...};
это идеально подходит для использования с ng-repeat / ng-class, вот так:
<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
и НЕ на item
объект
Есть ли способ напрямую расширить базовый класс, используемый для создания экземпляров объектов в списке?
Спасибо!
4 ответа
Я нашел эту проблему раньше, и решение, кажется, transformResponse
Джон Ледбеттер говорит в другом ответе.
В любом случае, если вам нужно сохранить весь объект, а также заполнить массив "items" экземплярами ресурса, вы можете сделать это с помощью следующего трюка:
Взяв пример из ответа Джона и немного его модифицировав:
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;
}]);
Если вы используете 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>
Недостатком этого является то, что вы теряете доступ к любому из внешних полей в вашем ответе, которые не находятся внутри элементов. Я все еще пытаюсь найти способ сохранить эти метаданные.
Это старый вопрос, но я сам столкнулся с этим вопросом. Решение 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;
});
Вы можете поместить метаданные в заголовок. Я всегда помещаю там данные подкачки. Таким образом, ваш запрос по-прежнему будет возвращать массив, что, я считаю, хорошо. Запросы должны возвращать массивы данных, а не отдельные данные.