最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Add methods to a collection returned from an angular resource query - Stack Overflow

programmeradmin0浏览0评论

I have a resource that returns an array from a query, like so:

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

Is it possible to add prototype methods to the array returned from this query? (Note, not to array.prototype).

For example, I'd like to add methods such as hasBookWithTitle(title) to the collection.

I have a resource that returns an array from a query, like so:

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

Is it possible to add prototype methods to the array returned from this query? (Note, not to array.prototype).

For example, I'd like to add methods such as hasBookWithTitle(title) to the collection.

Share Improve this question asked Mar 8, 2013 at 0:03 Marty PittMarty Pitt 29.3k38 gold badges130 silver badges204 bronze badges 1
  • See if this helps $resource relations in Angular.js. – Stewie Commented Mar 8, 2013 at 0:27
Add a ment  | 

3 Answers 3

Reset to default 5

The suggestion from ricick is a good one, but if you want to actually have a method on the array that returns, you will have a harder time doing that. Basically what you need to do is create a bit of a wrapper around $resource and its instances. The problem you run into is this line of code from angular-resource.js:

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

This is where the return value from $resource is set up. What happens is "value" is populated and returned while the ajax request is being executed. When the ajax request is pleted, the value is returned into "value" above, but by reference (using the angular.copy() method). Each element of the array (for a method like query()) will be an instance of the resource you are operating on.

So a way you could extend this functionality would be something like this (non-tested code, so will probably not work without some adjustments):

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;
});

Again, you will have to mess with it a bit, but that's the basic idea.

This is probably a good case for creating a custom service extending resource, and adding utility methods to it, rather than adding methods to the returned values from the default resource service.

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;
});

then

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

Looking at the code in angular-resource.js (at least for the 1.0.x series) it doesn't appear that you can add in a callback for any sort of default behavior (and this seems like the correct design to me).

If you're just using the value in a single controller, you can pass in a callback whenever you invoke query on the resource:

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

Alternatively, you can create a service which decorates the Books resource, forwards all of the calls to get/query/save/etc., and decorates the array with your method. Example plunk here: 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 */}
        );
      }
    };
  }
);

Thirdly, and I think this is better but it depends on your requirements, you can just take the functional approach and put the hasBookWithTitle function on your controller, or if the logic needs to be shared, in a utilities service.

发布评论

评论列表(0)

  1. 暂无评论