Adding methods to $resource objects

7,072 views
Skip to first unread message

Sean Gilligan

unread,
Jan 27, 2012, 2:21:54 AM1/27/12
to ang...@googlegroups.com
I see that resource objects get $save(), $remove(), and $delete()
methods added to what comes in the JSON.

Can you add your own methods to them? For example, in my app I need a
method that makes a call to the server, but then refreshes part of the
$resource object and possibly some associated objects. Let's say the
object is called Profile and call the method setFlag(). I could create
a service to do this like this:

$myservice.setFlag(profile)

or I could add a setFlag method to the profile and do this:

profile.setFlag()

There are pros and cons to each approach and it seems that Angular wants
to treat the $resource objects as simple data objects - with the
exception of $save() and $delete().

But I though I'd ask if it was possible to add methods. The related
question is, if it is possible, is it a good idea?

Thanks,

Sean


Daniel Nelson

unread,
Jan 27, 2012, 4:39:37 PM1/27/12
to ang...@googlegroups.com
On Fri, Jan 27, 2012 at 1:21 AM, Sean Gilligan <se...@msgilligan.com> wrote:
> I see that resource objects get $save(), $remove(), and $delete() methods
> added to what comes in the JSON.
>
> Can you add your own methods to them?

You can define your own methods. For example, I wanted to create verbs
that were inline with Ruby on Rails, so I added them as follows:

angular.service('SelectedPhotos', function($resource) {
return $resource('selected_photos/:selected_photo_id', {},
{ 'create': { method: 'POST' },
'index': { method: 'GET', isArray: true },
'update': { method: 'PUT' },
'destroy': { method: 'DELETE' }});
});

However, I wrote this for 0.9.x, and although it continued to work
until 0.10.5, it is broken in 0.10.6. I am at present trying to figure
out how to fix it, but without success thus far. I would be very
interested if someone from the AngularJS team would chime in on how to
define resources in 0.10.6.
http://docs-next.angularjs.org/api/angular.module.ng.$resource looks
like it should help, but the examples don't provide the surrounding
context, so I don't know what needs to be in place for the "x =
$resource" to work.

-Daniel

Sean Gilligan

unread,
Jan 27, 2012, 6:19:47 PM1/27/12
to ang...@googlegroups.com
On 1/27/12 1:39 PM, Daniel Nelson wrote:
> You can define your own methods. For example, I wanted to create verbs
> that were inline with Ruby on Rails, so I added them as follows:
>
> angular.service('SelectedPhotos', function($resource) {
> return $resource('selected_photos/:selected_photo_id', {},
> { 'create': { method: 'POST' },
> 'index': { method: 'GET', isArray: true },
> 'update': { method: 'PUT' },
> 'destroy': { method: 'DELETE' }});
> });

I've done this in 9.x, 10.5, *and* 10.6. But that's not what I'm asking
for.

I want to add some custom JavaScript methods to the resource object
using something like jQuery.extend()
Is there any explicit support for doing this? e.g. a way to specify
mix-ins that get automatically applied by Resource.get()?


> However, I wrote this for 0.9.x, and although it continued to work
> until 0.10.5, it is broken in 0.10.6.

(I can't share my code but let me take a look at it and might get back
you with some tips)

-- Sean

Sean Gilligan

unread,
Jan 27, 2012, 6:33:07 PM1/27/12
to ang...@googlegroups.com
On 1/27/12 3:19 PM, Sean Gilligan wrote:
> On 1/27/12 1:39 PM, Daniel Nelson wrote:
>> angular.service('SelectedPhotos', function($resource) {
>> return $resource('selected_photos/:selected_photo_id', {},
>> { 'create': { method: 'POST' },
>> 'index': { method: 'GET', isArray: true },
>> 'update': { method: 'PUT' },
>> 'destroy': { method: 'DELETE' }});
>> });
>> However, I wrote this for 0.9.x, and although it continued to work
>> until 0.10.5, it is broken in 0.10.6.
>
> (I can't share my code but let me take a look at it and might get back
> you with some tips)


1) added a module, like this:
var mym = angular.module('mym', []);

2) Changed service definitions from:
angular.service('Message', function($resource) {
to:
mym.factory('Message', function($resource) {

3) I also added the following config code:
mym.config(function($locationProvider, $httpProvider) {
// Configure existing providers
$httpProvider.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded';
$locationProvider.hashPrefix('!');
});

I had to do this because, I needed to override the default content-type
of "application/json".

I'm pretty sure those were the only changes needed to move the services
from 10.5 to 10.6.

-- Sean

Thierry Chatel

unread,
Jan 29, 2012, 7:18:58 AM1/29/12
to AngularJS
I don't know if you can add general methods to the data objects
returedn by your resource service, in addition to the ones you
configure as requests.

But adding methods to the service itself is easy, for a resource
service as for any service. In 0.10.6 (with modules), you can add any
method in a service factory :

var services = angular.module('myServices', []);
services.factory('Organisations', ['$resource', '$http',
function($resource, $http) {
var service = $resource('php/json_org_list.php', {}, {
'query' : {method : 'GET', isArray : true, verifyCache: true},
});
service.removeOrgs = function(ids, success, error) {
$http("POST", 'php/json_remove_orgs.php', {ids: ids}, success,
error);
};
return service;
}]);

The above example adds a "removeOrgs" methods, which uses the injected
$http service and makes a call to another server URL. You can add a
setFlag method like that, taking only your profile object as
parameter, and updating it in the success function passed to the $http
service.

Thierry Chatel

unread,
Jan 29, 2012, 11:22:13 AM1/29/12
to ang...@googlegroups.com
Well I tried adding a method to the retrieved objects, it's possible and easy :


var CreditCard = $resource('/user/:userId/card/:cardId',
 {userId:123, cardId:'@id'}, {
  charge: {method:'POST', params:{charge:true}}
 });
// Add a method that will be available in all retrieved CreditCard objects :
CreditCard.prototype.myMethod = function() {
   ...
};

// We can retrieve a collection from the server
var cards = CreditCard.query();

Johan Steenkamp

unread,
Jan 30, 2012, 1:51:33 AM1/30/12
to ang...@googlegroups.com
@Daniel

I got my services working in 0.10.6 using $provide as follows:

1. In the module 

angular.module('ngapp', [], function($locationProvider, $filterProvider, $provide, $httpProvider){
  $locationProvider.html5Mode(false).hashPrefix('!'); 

  $filterProvider.register('formatTitle', function(){
    return function(text) {
      return text ? '[' + text + ']' : '';
    }
  });

  $provide.factory('AppService', function($resource) {
    return $resource('../api/services.cfc', {}, {
      login: {method: 'POST', params: {'method': 'login'}},
      logout: {method: 'GET', params: {'method': 'logout'}},
      query: {method: 'GET', isArray: true},
      refresh: {method: 'GET', params: {'method': 'refresh'}},
      save: {method: 'POST', params: {'method': 'save'}}
    });
  });

});


Then in your controller:

AppCtrl.$inject = ['$route', '$location', 'AppService'];

function AppCtrl($route, $location, AppService) {
  window.$root = this.$root;

  var scope = this;
  scope.AppService = AppService;

  // use the service methods like this
  scope.AppService.login({username: scope.login.username, password: scope.login.password}, function(response){
    // work with response here
  });

  // some example routes
  $route.when('/', {template: 'partials/start.html', controller: StartCtrl});
  $route.when('/settings', {template: 'partials/settings.html', controller: SettingsCtrl});
  $route.when('/logout', {controller: LogoutCtrl});
  $route.when('/login', {template: 'partials/login.html'});
  $route.otherwise({redirectTo: '/'});
  $route.parent(scope); // allows child scopes to inherit from local scope


}


Misko Hevery

unread,
Jan 31, 2012, 12:10:01 PM1/31/12
to ang...@googlegroups.com
A resource is a Constructor function. That means you can methods like this

MyResource.prototype.myMethad = function() {};

and you can make one like this:
new MyResource();



}


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To view this discussion on the web visit https://groups.google.com/d/msg/angular/-/id2bPyhjKKoJ.

To post to this group, send email to ang...@googlegroups.com.
To unsubscribe from this group, send email to angular+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/angular?hl=en.

ThomasBurleson

unread,
Jan 31, 2012, 7:28:24 PM1/31/12
to AngularJS
@Johan, @Daniel,

Another way is:

// Constructor function
UserManager = function ( $http, $q, $log) {
// Your code here..
}

angular
.module( "ngapp", [] )
.factory( "AppService", ["$resource", function($resource) {
return $resource('.../api/services.cfc');
}])
.factory( "userManager", ['$http', '$q', '$log', function($http, $q,
$log){
return new UserManager($http, $q, $log);
}])
.run( AppCtrl )

Hope that helps.

On Jan 30, 12:51 am, Johan Steenkamp <johan.steenk...@gmail.com>
wrote:

ThomasBurleson

unread,
Jan 31, 2012, 7:31:08 PM1/31/12
to AngularJS
@Thierry - Nice.

Erik Dykema

unread,
Aug 19, 2013, 9:17:29 AM8/19/13
to ang...@googlegroups.com
Hello-

I am also attempting to add member methods to the objects retrieved by $resource.

I tried to follow the example that Thierry gave below, but one stumbling block is that we're building up our services using factories, rather than by creating the object constructors as in the CreditCard example.  Thus it is not clear (to me) how/where to access to the .prototype to add the extra methods.

So for example, there is the following definition of the Person service factory in our services.js file:

var svcmod = angular.module('MyApp.services', ['ngResource']);

svcmod.factory('Person', function($resource) {
        return $resource('/api/contacts/person/:id', {}, {
                query : {method:'GET'   , params:{id:''}, isArray:false},
                update: {method:'PUT'   , params:{id:'@id'}},
                delete: {method:'DELETE', params:{id:'@id'}}
            });
    });

Any suggestions on where/how, in this context, to put the extra method definitions?

thanks,
Erik

matthe...@hulu.com

unread,
Aug 20, 2013, 7:29:40 PM8/20/13
to ang...@googlegroups.com
This works for me:

var svcmod = angular.module('MyApp.services', ['ngResource']);

svcmod.factory('Person', function($resource) {
        var r = $resource('/api/contacts/person/:id', {}, {
                query : {method:'GET'   , params:{id:''}, isArray:false},
                update: {method:'PUT'   , params:{id:'@id'}},
                delete: {method:'DELETE', params:{id:'@id'}}
            });
        r.prototype.getInstanceIdString = function() {
          return "My instance id: " + this.id;
        }
        return r;
    });

Erik Dykema

unread,
Aug 21, 2013, 11:55:00 AM8/21/13
to ang...@googlegroups.com
Yep, that worked too.  Thanks.
Reply all
Reply to author
Forward
0 new messages