Подтвердить что ты не робот

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

Есть ли способ напрямую расширить базовый класс, используемый для создания объектов в списке?

Спасибо!

4b9b3361

Ответ 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

Вы можете поместить метаданные в заголовок. Я всегда размещаю данные подкачки. Таким образом, ваш запрос по-прежнему будет возвращать массив, который, я считаю, хорош. Запросы должны возвращать массивы данных, а не отдельные данные.