Reputation: 11543
Is it possible to add virtual attributes to a ngResource? I created a service like this
app.factory('Person', ['$resource', function($resource) {
return $resource('api/path/:personId', {
personId: '@_id'
}, {
update: {
method: 'PUT'
}
});
}])
Person
has an attribute name
and an attribute surname
.
I want to retrive the fullname
by adding a virtual attribute fullname
returning resource.name + resource surname
.
I know I could add it in 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 it doesn't work.
Upvotes: 7
Views: 780
Reputation: 1312
Khanh TO put me on the way to a working answer for me, but, as explained in this Angular ticket, in the interceptor, you have to handle and return response.resource
instead of response
.
Here is a solution (working 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;
}
}
}
});
}]);
Upvotes: 1
Reputation: 48972
You could try intercepting the response from the Person resource and augment 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;
}
}}
});
}]);
Upvotes: 4
Reputation: 496
If you only need the derived property for display purposes, you can create a display filter rather than loading up your model with redundant data:
app.filter('personFullName', function() {
return function(person) {
return person.name + " " + person.surname;
};
})
Then reference the filter in your template:
<div>
<p>{{person | personFullName}}</p>
<p>- should match -</p>
<p>{{person.name}} {{person.surname}}</p>
</div>
Upvotes: 2
Reputation: 40298
As per the docs, $resource
returns a constructor. You can leverage the usual prototype
of the 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
can be anything normally allowed in a prototype. If what you want is actually a derived property, i.e. a JS property that will always reflect the name
and surname
properties, then you need a fairly recent browser that supports Object.defineProperty()
and replace the Person.prototype
line above with:
Object.defineProperty(
Person.prototype,
"fullname",
{get: function() { return this.name + " " + this.surname; }}
);
Upvotes: 4