我有一个模型,使用定义$resource
,是我成功加载。
每个加载的实例是,如许,我所定义的类的实例。
(下面的例子是从角文档。在这里面, User.get
导致一个对象,它是一个instanceof User
)。
var User = $resource('/user/:userId', {userId:'@id'});
然而,可以想象每个用户过来这样的线:
{
"username": "Bob",
"preferences": [
{
"id": 1,
"title": "foo",
"value": false
}
]
}
我定义了一个Preference
的工厂,增加了宝贵的方法来Preference
对象。 但是,当用户的负荷,这些preferences
并不Preference
S,自然。
我尝试这样的:
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
}
但它没有任何效果,从来没有记录任何东西。
我怎样才能让我的每一个项目User
s'的preferences
阵列的一个实例Preference
?
Answer 1:
$资源是一个简单的实现,并在这样的事情缺乏。
User.prototype.constructor
不会做任何事情; 角不会尝试像它的面向对象,不像其他库。 这只是JavaScript的。
..但幸运的是,你有承诺和JavaScript :-)。 这里有一个方法,你可以这样做:
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);
};
你可以抽象成装饰中的任何一种资源的方法的方法是:它需要一个对象,方法名的数组和装饰功能。
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);
Answer 2:
您可以通过覆盖内置资源行动来改变请求和响应做到这一点(见transformRequest和transformResponse的文档 。):
var m = angular.module('my-app.resources');
m.factory('User', [
'$resource',
function($resource) {
function transformUserFromServer(user) {
// Pass Preference directly to map since, in your example, it takes a JSON preference as an argument
user.preferences = _.map(user.preferences, Preference);
return user;
}
function transformUserForServer(user) {
// Make a copy so that you don't make your existing object invalid
// E.g., changes here may invalidate your model for its form,
// resulting in flashes of error messages while the request is
// running and before you transfer to a new page
var copy = angular.copy(user);
copy.preferences = _.map(user.preferences, function(pref) {
// This may be unnecessary in your case, if your Preference model is acceptable in JSON format for your server
return {
id: pref.id,
title: pref.title,
value: pref.value
};
});
return copy;
}
function transformUsersFromServer(users) {
return _.map(users, transformUserFromServer);
}
return $resource('/user/:userId', {
userId: '@id'
}, {
get: {
method: 'GET',
transformRequest: [
angular.fromJson,
transformUserFromServer
]
},
query: {
method: 'GET',
isArray: true,
transformRequest: [
angular.fromJson,
transformUsersFromServer
]
},
save: {
method: 'POST',
// This may be unnecessary in your case, if your Preference model is acceptable in JSON format for your server
transformRequest: [
transformUserForServer,
angular.toJson
],
// But you'll probably still want to transform the response
transformResponse: [
angular.fromJson,
transformUserFromServer
]
},
// update is not a built-in $resource method, but we use it so that our URLs are more RESTful
update: {
method: 'PUT',
// Same comments above apply in the update case.
transformRequest: [
transformUserForServer,
angular.toJson
],
transformResponse: [
angular.fromJson,
transformUserFromServer
]
}
}
);
};
]);
Answer 3:
我一直在寻找一个解决同样的问题你。 我想出了以下的方法。
这个例子是基于优惠而不是用户,域的实体。 另外,请注意这里的整个事情,这在我的情况下,跨越了一些文件下调版本:
域实体自定义类:
function Offer(resource) {
// Class constructor function
// ...
}
angular.extend(Offer.prototype, {
// ...
_init: function (resource) {
this._initAsEmpty();
if (typeof resource == 'undefined') {
// no resource passed, leave empty
}
else {
// resource passed, copy offer from that
this.copyFromResource(resource);
}
},
copyFromResource: function (resource) {
angular.extend(this, resource);
// possibly some more logic to copy deep references
},
// ...
});
经典角自定义资源:
var offerResource = $resource(/* .. */);
自定义库,通过由服务工厂到控制器:
function OfferRepository() {
// ...
}
angular.extend(OfferRepository.prototype, {
// ...
getById: function (offerId, success, error) {
var asyncResource = offerResource.get({
offerId: offerId
}, function (resource) {
asyncOffer.copyFromResource(resource);
(success || angular.noop)(asyncOffer);
}, function (response) {
(error || angular.noop)(response);
});
var asyncOffer = new offerModels.Offer(asyncResource);
return asyncOffer;
},
// ...
});
最引人注目的部分是:
- 自定义实体类,即能构建/填充自己从一个资源实例(可能与深拷贝能力,例如在报价位置)开始
- 自定义库类,它封装了资源。 这并不返回经典的异步资源的答案,而是返回自定义实体实例,后来它填补了这个与资源只是加载。
Answer 4:
试图修改原型对象你期望什么,无论如何不会做的constructor属性,请看看很不错的职位在这里 。
要真正了解是怎么回事,应该看看源代码中的ngResource
模块-有很多东西在那里工作,但什么是最重要的是, $resource
工厂返回一个普通的JavaScript函数(真的,还有什么) 。 调用此功能与记录参数返回一个Resource
构造对象,这是在专门定义resourceFactory
。
你可能还记得,AngularJS服务是单身,这意味着调用$resource
将每次返回相同的功能(在这种情况下, resourceFactory
)。 最重要的外卖是每一个这种功能进行评价的时候,一个新的Resource
返回构造的对象,也就是说,你可以在上面安全地原型自己的功能,而无需担心这会污染所有Resource
在全球范围的实例。
这里是您可以使用多达原有服务$resource
工厂,而定义自己的自定义方法,将适用于所有的实例:
angular.module('app').factory('ExtendedResourceFactory', ['$resource',
function($resource) {
function ExtendedResourceFactory() {
var Resource = $resource.apply(this, arguments);
Resource.prototype.myCustomFunction = function() {
...
};
return Resource;
}
return ExtendedResourceFactory;
}
]);
里面myCustomFunction
您可以访问从服务器返回的,所以你可以使用数据this.preferences
并返回你想建立取其自定义类。
Answer 5:
transformResponse
做这项工作。 考虑例子(我想用Autolinker格式化响应内容)。
return $resource('posts/:postId', {
postId: '@_id'
}, {
get : {
transformResponse : function(data) {
var response = angular.fromJson( data );
response.content = Autolinker.link(response.content);
return response;
}
},
update: {
method: 'PUT'
} });
文章来源: How can I extend the constructor of an AngularJS resource ($resource)?