我有一个模型,定义使用$resource
,我成功加载.
正如所承诺的,每个加载的实例都是我定义的类的实例.
(以下示例来自Angular文档.在其中,User.get
结果是一个对象instanceof User
.)
var User = $resource('/user/:userId', {userId:'@id'});
但是,想象每个用户来自这样的电线:
{ "username": "Bob", "preferences": [ { "id": 1, "title": "foo", "value": false } ] }
我定义了一个Preference
为Preference
对象添加有价值方法的工厂.但是当用户加载时,这些preferences
不是Preference
自然的.
我试过这个:
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
?
$ resource是一个简单的实现,缺少这样的东西.
User.prototype.constructor
什么都不做; 与其他库不同,angular不会尝试像面向对象那样行事.这只是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);
您可以通过覆盖内置资源操作来转换请求和响应来执行此操作(请参阅文档中的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 ] } } ); }; ]);