[英]Angular 2 own Class Decorator to access Dependency Injection Service
I want to create a class decorator TopicClass
which adds a property and a function to the decorated component.我想创建一个类装饰器
TopicClass
,它向装饰组件添加一个属性和一个函数。 The function must access a injected Service.该函数必须访问注入的服务。 How do I do that?
我怎么做?
Here is what tried unsuccessfully:以下是尝试失败的内容:
@Component({
selector: 'home',
styleUrls: ['./home.component.css'],
templateUrl: './home.component.html'
})
@TopicClass('home')
export class HomeComponent {
constructor(private topicService: TopicService) { }
}
I cannot access the injected Service through the inserted function ngAfterViewInit
.我无法通过插入的函数
ngAfterViewInit
访问注入的 Service。
export function TopicClass(title: string) {
return function (target: Function) {
const original = target;
function construct(constructor, args) {
const c: any = function () {
return constructor.apply(this, args);
}
c.prototype = constructor.prototype;
const newInstance = new c();
newInstance['topic'] = new Topic(title, '');
newInstance['ngAfterViewInit'] = () => {
newInstance['topicService'].setTopic(newInstance['topic']);
}
return newInstance;
}
const ctor: any = (...args) => {
console.log("Service: " + original.prototype.topicService);
return construct(original, args);
};
ctor.prototype = original.prototype;
return ctor;
}
}
The problem is newInstance['topicService']
is undefined.问题是
newInstance['topicService']
未定义。
I have set up a simple Angular project for testing: https://github.com/ptea/angular-class-decorator-test我已经建立了一个简单的 Angular 项目进行测试: https : //github.com/ptea/angular-class-decorator-test
https://github.com/ptea/angular-class-decorator-test/blob/master/src/app/services/topic.service.ts https://github.com/ptea/angular-class-decorator-test/blob/master/src/app/services/topic.service.ts
I also tried to reproduce the problem with a simple TypeScript program, which works as intended:我还尝试用一个简单的 TypeScript 程序重现这个问题,它按预期工作:
newInstance['printStreet'] = () => {
console.log(`printFirstnameStreet: ${newInstance['firstname']}, ${newInstance['street']}`);
}
https://github.com/ptea/angular-class-decorator-test/blob/master/dashboard.ts https://github.com/ptea/angular-class-decorator-test/blob/master/dashboard.ts
Any ideas/solution to this problem?这个问题的任何想法/解决方案?
The reason that the TopicService
is undefined is because it was never injected into the component. TopicService
未定义的原因是因为它从未被注入到组件中。 With your current decorator it is redefining the constructor of the HomeComponent
to be a constructor that has no arguments.根据您当前的装饰被重新定义的构造
HomeComponent
是没有参数的构造函数。 This is messing up Angular's DI and so the TopicService
is not injected when the Component is instantiated.这弄乱了 Angular 的 DI,因此在实例化组件时不会注入
TopicService
。
The best way I can think of to accomplish what you want is to not modify the constructor of the HomeComponent
and instead tap into the ngOnInit
method instead.我能想到的来完成你想要什么,最好的办法是不能修改的构造
HomeComponent
,转而进军ngOnInit
方法来代替。 The ngOnInit method is an ideal candidate because it is called once per the component's lifecycle and it has a fixed number of parameters, 0, which makes it easy to wrap inside another function. ngOnInit 方法是一个理想的候选方法,因为它在每个组件的生命周期中被调用一次,并且它有固定数量的参数,0,这使得它很容易包装在另一个函数中。 You can similarity do this with the
ngAfterViewInit
function to use the service when desired.您可以与
ngAfterViewInit
函数类似地执行此操作,以便在需要时使用该服务。
Here is how you could modify the TopicClassDecorator
to acheive your desired result:以下是如何修改
TopicClassDecorator
以实现您想要的结果:
export function TopicClass(title: string) {
return function (target: Function) {
let targetNgOnInit = target.prototype.ngOnInit;
target.prototype.ngOnInit = function (){
this.topic = new Topic(title, 'subTitle');
if(targetNgOnInit){
targetNgOnInit.apply(target);
}
}
let targetNgAfterViewInit = target.prototype.ngAfterViewInit;
target.prototype.ngAfterViewInit = function (){
this.topicService.setTopic(this.topic);
if(targetNgAfterViewInit){
targetNgAfterViewInit.apply(target);
}
}
return target;
}
}
Demo Plunkr of everything working together.一切协同工作的演示 Plunkr 。
I finally went with the following solution without overriding the ngOnInit function:我终于在不覆盖 ngOnInit 函数的情况下采用了以下解决方案:
export function TopicClass(title: string) {
return function (target: Function) {
target.prototype.topic = new Topic(title);
let targetNgAfterViewInit = target.prototype.ngAfterViewInit;
target.prototype.ngAfterViewInit = function () {
this.topicService.setTopic(this.topic);
if(targetNgAfterViewInit){
targetNgAfterViewInit.apply(target);
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.