37

在大多数情况下,<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

4 回答 4

53

transformResponse正如John Ledbetter 在另一个答案中所说,我以前发现过这个问题,并且解决方案似乎是。

无论如何,如果您需要保留整个 object,并且还需要在“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;
  }]);
于 2013-06-17T14:11:30.150 回答
9

如果您使用的是 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>

这样做的缺点是您无法访问响应中不在项目内部的任何外部字段。我仍在努力寻找一种方法来保留该元数据。

于 2013-06-16T15:34:46.287 回答
4

这是一个老问题,但我自己也遇到了这个问题。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;
    });
于 2015-01-04T18:25:34.110 回答
0

您可以将元数据放在标题中。我总是把分页数据放在那里。这样你的查询仍然会返回一个数组,我相信这是一件好事。查询应该返回数据数组,而不是单个数据。

于 2015-11-22T20:37:33.217 回答