Virtual Attributes in ngResource

Can virtual attributes be added to ngResource? I created such a service

app.factory('Person', ['$resource', function($resource) { return $resource('api/path/:personId', { personId: '@_id' }, { update: { method: 'PUT' } }); }]) 

Person has a name attribute and a surname attribute.
I want to extract fullname by adding a virtual fullname attribute that returns resource.name + resource surname .
I know that I can add it to the controller, but adding it to the service, it will make it much more portable. I tried something like this

 app.factory('Person', ['$resource', function($resource) { return $resource('api/path/:personId', { personId: '@_id' }, { update: { method: 'PUT' }, fullname: function(resource){ return resource.name + ' ' + resource.surname; } }); }); }]) 

but that will not work.

+7
angularjs ngresource
source share
4 answers

You can try to intercept the response from the Person resource and increase the response. Like this:

 app.factory('Person', ['$resource', function($resource) { function getFullName(){ return this.name + ' ' + this.surname; }; return $resource('api/path/:personId', { personId: '@_id' }, { update: { method: 'PUT' }, 'get': {method:'GET', isArray:false,interceptor:{ 'response': function(response) { response.fullname = getFullName; //augment the response with our function return response; } }} }); }]); 
+4
source share

According to the docs, $resource returns a constructor. You can use the regular prototype constructor to add members, i.e.:

 var Person = $resource('api/path/:personId', { personId: '@_id' }, { update: { method: 'PUT' } }); // same as the 1st snippet from the question Person.prototype.xxxx = ...; return Person; // from your Angular service 

In the previous example, xxxx might be something that is normally allowed in the prototype. If you really want to get a derived property, that is, a JS property that will always reflect the name and surname properties, then you will need a fairly recent browser that supports Object.defineProperty() and replaces the Person.prototype line above:

 Object.defineProperty( Person.prototype, "fullname", {get: function() { return this.name + " " + this.surname; }} ); 
+4
source share

If display requires only a derived property, you can create a display filter rather than loading your model with redundant data:

 app.filter('personFullName', function() { return function(person) { return person.name + " " + person.surname; }; }) 

Then specify the filter in the template:

 <div> <p>{{person | personFullName}}</p> <p>- should match -</p> <p>{{person.name}} {{person.surname}}</p> </div> 
+2
source share

Khanh TO put me on the path of a working answer for me, but as explained in this Angular ticket , in the interceptor you should process and return response.resource instead of response .

Here is the solution (works for Angular 1.4):

 app.factory('Person', ['$resource', function($resource) { return $resource( 'api/path/:personId', {personId: '@_id'}, { update: {method: 'PUT'}, get: { method: 'GET', isArray: false, interceptor: { response: function(response) { var resource = response.resource; resource.fullname = resource.name + ' ' + resource.surname; return resource; } } } }); }]); 
+1
source share

All Articles