我有一个基本服务,如下所示:
.service('BaseImageService', ['$q', 'ApiHandler', 'UploadService', function ($q, api, uploadService) {
// Get our api path
var apiPath = 'logos';
// Creates our logo
var _createLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.post(apiPath, model);
});
};
// Edit our logo
var _editLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.put(apiPath, model);
});
};
// Handles our files
var _handleUploads = function (model) {
// Create a promises array
var promises = [];
// Get our file
var file = model.file,
old = model.old;
// If we have a file
if (file) {
// Try to upload the file
promises.push(uploadService.upload(model.file).then(function (response) {
// Update our model
model.path = response.path;
model.thumbnail = response.thumbnail;
}));
// If we have an old model
if (old) {
// Delete both our files
promises.push(uploadService.delete(old.path));
promises.push(uploadService.delete(old.thumbnail));
}
}
// After all promises have completed
return $q.all(promises);
};
// Create our service
var service = {
// Update our api path
updateApiPath: function (path) {
// Set the api path
apiPath = path;
},
// Gets a list of logos
list: function (t) {
if (t) {
console.log(apiPath);
}
// Get our logo
return api.get(apiPath);
},
// Get a single logo
get: function (id) {
// Get our logo
return api.get(apiPath, { id: id });
},
// Create our logo
save: function (model) {
// If we are editing
if (model.id) {
// Edit our logo
return _editLogo(model);
// If we are creating
} else {
// Create our logo
return _createLogo(model);
}
},
// Deletes our logo
delete: function (id) {
// Delete our logo
return api.delete(apiPath, { id: id });
},
// Prepare for editing
prepareForEditing: function (model) {
// Create our old object
model.old = {
path: model.path,
thumbnail: model.thumbnail
};
}
};
// Return our service
return service;
}])
然后我有一些“继承”此服务的服务,如下所示:
.service('ImageService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'images';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
.service('LogoService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'logos';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
.service('PlayerTextService', ['BaseImageService', function (baseService) {
// Get our api path
var apiPath = 'playerText';
// Update the apiPath
baseService.updateApiPath(apiPath);
// Return our service
return baseService;
}])
我认为这很好用。但我有这个页面顺序调用所有3个服务(ImageService,LogoService和PlayerTextService)。在页面的第一个视图上一切都很好,如果我离开然后回来图像服务实际上从播放器文本服务拉回东西。现在我知道这是因为服务是单身人士,但我不知道如何解决我的问题。
任何人都可以帮我一把吗?
我添加了一个尝试解决方案的codepen:
http://codepen.io/r3plica/pen/ONVBJO
尝试2
答案 0 :(得分:2)
您尝试的解决方案不起作用,因为BaseService是一个单例。因此,您将完全相同的实例注入所有三个服务注册函数,并且所有这些函数都配置相同的对象。所以基本上最后一个赢了。
看起来您希望使用不同配置的单独服务。这就是供应商的用途。它们允许构建服务实例的两步过程。请参阅以下主题的Stackoverflow答案:
AngularJS: Service vs provider vs factory
作为参考,Restangular是一个需要完全相同的库。您可以将其用作蓝图,并查看Restangular如何处理此要求:
请注意,这些概念基于AngularJS 1,如果您希望稍后使用AngularJS 2,则需要以不同方式处理。
答案 1 :(得分:2)
经过大量的捣乱;我终于找到了解决方案adapting this bit of code
我的基本服务如下:
.factory('BaseImageService', ['$q', 'ApiHandler', 'UploadService', 'vectorExtensions', function ($q, api, uploadService, vectorExtensions) {
// Creates our logo
var _createLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.post(BaseImageService.apiPath, model);
});
};
// Edit our logo
var _editLogo = function (model) {
// Handle our uploads
return _handleUploads(model).then(function () {
// Create our logo
return api.put(BaseImageService.apiPath, model);
});
};
// Handles our files
var _handleUploads = function (model) {
// Create a promises array
var promises = [];
// Get our file
var file = model.file,
old = model.old;
// If we have a file
if (file) {
// Try to upload the file
promises.push(uploadService.upload(model.file).then(function (response) {
// Update our model
model.path = response.path;
model.thumbnail = response.thumbnail;
model.fileName = response.fileName;
}));
// If we have an old model
if (old) {
// Delete both our files
promises.push(uploadService.delete(old.path));
promises.push(uploadService.delete(old.thumbnail));
}
}
// After all promises have completed
return $q.all(promises);
};
// Addes a property to the image array to state if they are vector images or not
var _addVectorProperties = function (images) {
// Loop through our images
for (var i = 0; i < images.length; i++) {
// Get our current image
var image = _addVectorProperty(images[i]);
}
// Return our images
return images;
};
// Adds a property to the image to state if it is vector or not
var _addVectorProperty = function (image) {
// Vector flag
var vector = false;
// Get our file extension
var parts = image.path.split('.');
// If we have any parts
if (parts.length) {
// Get our last part
var ext = parts[parts.length - 1],
index = vectorExtensions.indexOf(ext);
// If our extension exists in our vector array
if (index > -1) {
// Change our vector property
vector = true;
}
}
// Update our image with the new property
image.vector = vector;
// Return our image
return image;
};
// Create our service
var BaseImageService = function (path) {
// Set our apiPath
this.apiPath = path;
// Update our api path
this.updateApiPath = function (path) {
// Set the api path
apiPath = path;
};
// Gets a list of logos
this.list = function () {
// Get our logo
return api.get(this.apiPath).then(_addVectorProperties);
};
// Get a single logo
this.get = function (id) {
// Get our logo
return api.get(this.apiPath, { id: id }).then(_addVectorProperty);
};
// Create our logo
this.save = function (model) {
// If we are editing
if (model.id) {
// Edit our logo
return _editLogo(model);
// If we are creating
} else {
// Create our logo
return _createLogo(model);
}
};
// Deletes our logo
this.delete = function (id) {
// Delete our logo
return api.delete(this.apiPath, { id: id });
};
// Set our active image
this.setActive = function (images, image) {
// Loop through our images
for (var i = 0; i < images.length; i++) {
// Get our current image
var current = images[i];
// Set whether we are active or not
current.active = image.id === current.id ? true : false;
}
};
// Prepare for editing
this.prepareForEditing = function (model) {
// Create our old object
model.old = {
path: model.path,
thumbnail: model.thumbnail
};
};
};
// Return our service
return BaseImageService;
}])
并且子服务看起来像这样:
.service('ImageService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('images');
// Return our new service
return child;
}])
.service('LogoService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('logos');
// Return our new service
return child;
}])
.service('PlayerTextService', ['BaseImageService', function (baseService) {
// Create our base service
var child = new baseService('playerText');
// Return our new service
return child;
}])
工作正常。
答案 2 :(得分:0)
是的,它会附加,因为它是单身人士。如果要执行此操作,则必须执行继承。
这是我使用的代码并附加到angular:
angular.baseResourceServiceMaker = function(service){
return ['$injector', '$resource', 'TypeService', '$http', '_', 'BackEndpoint',
function($injector, $resource,TypeService, $http, _, BackEndpoint){
//skipping not interesting code
// sample fields to inherits
this.sample = "test";
this.sampleFN = function(){[...]}
// THE line that does the magic
$injector.invoke(service, this);
}
现在使用时间
.service('MyService',angular.baseResourceServiceMaker(['$http', function($http){
// overriding fields
this.sample="inherits";
this.sampleFN = function(){[...]}
}]));
基本上我们在这里有什么?函数baseResourceServiceMaker,表示通用特定服务。调用我们想要实例化的服务的$ injector,并将范围设置为泛型服务,因此子类上的this将绑定到与泛型类相同的引用。通用服务将被实例化为您调用它的次数,没有任何混淆。
我个人使用此代码作为angular的资源模块来定义一些具有自定义序列化器/解串器的基本方法,而不是处理日期和其他一些东西。在您的情况下,baseResourceServiceMaker将是您的baseImageService,以$ injector.invoke(service,this)结尾。
编辑:找到了一些可能更干净的链接:AngularJS service inheritance
答案 3 :(得分:0)
如果您使用(或切换到)ES6或TypeScript,这将变得非常容易。
export class Base {
// . . .
}
然后:
import {app} from '../app';
import {Base} from './base';
export class Child extends Base {
// . . .
}
app.service('child', Child);
答案 4 :(得分:0)
从你的尝试1:
BaseService
在全球范围内寻找apiPath
,list()
方法,apiPath
将引用全球级声明值的所有方式,即来自第2步的apiPath = 'images';
解决方案:在this
和apiPath
下的BaseService
前面使用list()
运算符。
工作Plunker