I have a model, defined using $resource
, that I am successfully loading.
Each loaded instance is, as promised, an instance of the class I defined.
(The example below is from the Angular docs. In it, User.get
results in an object that is an instanceof User
.)
var User = $resource('/user/:userId', {userId:'@id'});
However, imagine each User comes over the wire like this:
{
"username": "Bob",
"preferences": [
{
"id": 1,
"title": "foo",
"value": false
}
]
}
I defined a Preference
factory that adds valuable methods to Preference
objects. But when a User loads, those preferences
aren’t Preference
s, naturally.
I attempted this:
User.prototype.constructor = function(obj) {
_.extend(this, obj);
this.items = _.map(this.preferences, function(pref) {
return new Preference(pref);
});
console.log('Our constructor ran'); // never logs anything
}
But it has no effect and never logs anything.
How can I make each item in my User
s’ preferences
array an instance of Preference
?
$resource is a simple implementation, and lacks in things like this.
User.prototype.constructor
won't do anything; angular doesn't try to act like it's object oriented, unlike other libraries. It's just javascript.
..But luckily, you have promises and javascript :-). Here's a way you could do it:
function wrapPreferences(user) {
user.preferences = _.map(user.preferences, function(p) {
return new Preference(p);
});
return user;
}
var get = User.get;
User.get = function() {
return get.apply(User, arguments).$then(wrapPreferences);
};
var $get = User.prototype.$get;
User.prototype.$get = function() {
return $get.apply(this, arguments).$then(wrapPreferences);
};
You could abstract this into a method which decorates any of a resource's methods: It takes an object, an array of method names, and a decorator function.
function decorateResource(Resource, methodNames, decorator) {
_.forEach(methodNames, function(methodName) {
var method = Resource[methodName];
Resource[methodName] = function() {
return method.apply(Resource, arguments).$then(decorator);
};
var $method = Resource.prototype[methodName];
Resource.prototype[methodName] = function() {
return $method.apply(this, arguments).$then(decorator);
};
});
}
decorateResource(User, ['get', 'query'], wrapPreferences);