将方法添加到角度资源查询返回的集合

时间:2013-03-08 00:03:07

标签: javascript angularjs

我有一个从查询中返回数组的资源,如下所示:

.factory('Books', function($resource){
    var Books = $resource('/authors/:authorId/books');
    return Books;
})

是否可以将原型方法添加到从此查询返回的数组中? (注意,不要array.prototype)。

例如,我想将hasBookWithTitle(title)等方法添加到集合中。

3 个答案:

答案 0 :(得分:5)

来自ricick的建议很好,但是如果你想在返回的数组上实际拥有一个方法,那么你将很难做到这一点。基本上你需要做的是创建一个围绕$ resource及其实例的包装器。您遇到的问题是来自angular-resource.js的这行代码:

var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));

这是设置$ resource的返回值的地方。在执行ajax请求时,会填充并返回“value”。当ajax请求完成时,该值将返回到上面的“value”,但是通过引用(使用angular.copy()方法)。数组的每个元素(对于像query()这样的方法)将是您正在操作的资源的实例。

所以你可以扩展这个功能的方式是这样的(未经过测试的代码,所以如果没有一些调整就可能无法工作):

var myModule = angular.module('myModule', ['ngResource']);
myModule.factory('Book', function($resource) {
    var service = $resource('/authors/:authorId/books'),
        origQuery = service.prototype.$query;

    service.prototype.$query = function (a1, a2, a3) {
        var returnData = origQuery.call(this, a1, a2, a3);
        returnData.myCustomMethod = function () {
            // Create your custom method here...
        return returnData;
        }
    }

    return service;
});

同样,你将不得不捣乱它,但这是基本的想法。

答案 1 :(得分:4)

这可能是创建自定义服务扩展资源并向其添加实用程序方法的好例子,而不是向默认资源服务的返回值添加方法。

var myModule = angular.module('myModule', []);
myModule.factory('Book', function() {
    var service = $resource('/authors/:authorId/books');
    service.hasBookWithTitle = function(books, title){
        //blah blah return true false etc.
    }
    return service;
});

然后

books = Book.list(function(){
    //check in the on complete method
    var hasBook = Book.hasBookWithTitle(books, 'someTitle');
})

答案 2 :(得分:2)

查看angular-resource.js中的代码(至少对于1.0.x系列),您似乎无法为任何类型的默认行为添加回调(这似乎是正确的设计)我)。

如果您只是在单个控制器中使用该值,则只要在资源上调用query,就可以传入回调:

var books = Book.query(function(data) {
    data.hasBookWithTitle = function (title) { ... };
]);

或者,您可以创建一个装饰Books资源的服务,将所有调用转发到get / query / save / etc.,并使用您的方法装饰数组。插入示例:http://plnkr.co/edit/NJkPcsuraxesyhxlJ8lg

app.factory("Books",
  function ($resource) {
    var self = this;
    var resource = $resource("sample.json");

    return {
      get: function(id) { return resource.get(id); },
      // implement whatever else you need, save, delete etc.
      query: function() {
        return resource.query(
          function(data) { // success callback
            data.hasBookWithTitle = function(title) {
              for (var i = 0; i < data.length; i++) { 
                if (title === data[i].title) {
                  return true;
                }
              }
              return false;
            };
          },
          function(data, response) { /* optional error callback */}
        );
      }
    };
  }
);

第三,我认为这更好,但这取决于您的要求,您可以采用功能方法并将hasBookWithTitle函数放在您的控制器上,或者如果逻辑需要在实用程序服务中共享。