我很难理解如何在Angular2中扩展服务。
我有一个连接到Firebase的服务,并执行各种常见任务(获取,设置,更新,列表等),而不是为我的特殊组件重新编写它,我尝试只是扩展它。
我的想法是,我只能传递路径的新部分,但会引发错误:
Cannot resolve all parameters for 'FirebaseService'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'FirebaseService' is decorated with Injectable.
问题在于构造函数和我缺乏OOP的大脑。我可以将其他服务或提供者传递给我的服务,但我不能再传递简单的字符串参数,除非我遗漏了一些东西。我尝试设置属性,但我认为我没有正确的上下文。
我认为这是@Injectable的一个问题,但我不确定。
这是我首先尝试的简化版本:
更新包含PLUNKER链接:
Plunker for passing with parameters
Plunker for passing with constructor
@Injectable()
export class FirebaseService {
rootPath:string = "https://mysite.firebase.com/";
childPath:string;
pathToUse: string;
constructor() {
if(this.childPath){
this.pathToUse = this.rootPath + this.childPath;
}else{
this.pathToUse = this.rootPath;
}
console.log(this.pathToUse);
}
}
//The in project_service.ts
@Injectable()
export class ProjectService extends FirebaseService{
childPath:string = "projects";
constructor(){
super();
}
}
我预计它会附加“项目”行。它没有,它只是重复。
所以然后我尝试通过构造函数:
@Injectable()
export class FirebaseService {
rootPath:string = "https://mysite.firebase.com";
pathToUse: string;
constructor(childPath:string) {
if(childPath){
this.pathToUse = this.rootPath + childPath;
}else{
this.pathToUse = this.rootPath;
}
console.log(this.pathToUse);
}
}
//The in project_service.ts
@Injectable()
export class ProjectService extends FirebaseService{
constructor(){
super('projects');
}
}
哪一切都搞砸了。我有办法解决它,但它似乎完全是黑客攻击。
将“projects”参数传递给父类的正确方法是什么?
答案 0 :(得分:8)
所以在经过CH Buckingham的一些好工作之后,我已经解决了这样做的“典型”方式是不可能的。
Angular2只需使用注入器接管构造函数()函数。然而,有什么工作可以创建一个备用的“init”函数,然后可以将参数传递给它。
@Injectable()
export class ParentService {
root:string = "This content comes from: ";
myString:string = "The Parent";
resultString:string;
constructor(){
this.init();
}
init() {
this.resultString = this.root + this.myString;
}
}
@Injectable()
export class ChildService extends ParentService {
constructor(){
super();
}
init() {
this.myString = "The Child";
super.init();
}
}
通过这种方式,您可以在子对象上设置值或将它们传递给父对象。
答案 1 :(得分:5)
这是在angular2中扩展服务的另一种方法,它与DI一起使用。子服务不能对父进程使用的可注入服务使用相同的参数名,因此是anotherHttp参数名的原因。
父服务:
@Injectable()
export class GenericStore {
....
constructor(public config:GenericConfig,private http:Http) {
....
}
....
}
儿童服务:
const DEFAULT_CONFIG:GenericConfig = { ... };
@Injectable()
export class ConfigStore extends GenericStore {
....
constructor(private anotherHttp:Http) {
super(DEFAULT_CONFIG,anotherHttp);
}
....
}
答案 2 :(得分:2)
更新:如果你想使用没有手动实例化的标准服务接口并将简单值传递给构造函数,那么文档建议设置一个工厂,它需要几乎愚蠢的代码: Dependency Injection(向下滚动到工厂提供商)。
//this is all Google Example Code
constructor(private logger: Logger, private useCoolFeature: boolean) {}
let heroServiceFactory = (logger: Logger, userService: UserService) => {
return new HeroService(logger, userService.user.isSpecial);
}
let heroServiceDefinition = {
useFactory: heroServiceFactory,
deps: [Logger, UserService]
};
let heroServiceProvider = provide(HeroService, heroServiceDefinition);
bootstrap(AppComponent, [heroServiceProvider, Logger, UserService]);
以下代码可正常运行,但不使用提供商系统进行服务:
//things.service.ts
@Injectable()
export class ThingService {
public myString: string = "base";
constructor(str: string) {
this.myString = str;
}
}
@Injectable()
export class Thing2Service extends ThingService {
constructor(){
super('I AM CHILD');
}
}
//app.component.ts
public thingService: ThingService = new ThingService("I AM PARENT");
public thing2Service: Thing2Service = new Thing2Service();
ThingService.myString === "I AM PARENT"; //true
Thing2Service.myString === "I AM CHILD"; //true
答案 3 :(得分:2)
最好的方式IMO是使用抽象属性。这样,扩展类将强制以提供必需的值。
abstract class GenericStore{
abstract configVal: string;
constructor(){}
someMethod(){
console.log('The config value is:', this.configVal);
}
}
class UserStore extends GenericStore{
configVal = 'A config value. Typescript will yell if not provided.';
constructor(){
super();
}
}