说我有以下标记:
<my-comp myDirective></my-comp>
我有什么方法可以从指令访问组件实例?
更具体地说,我希望能够从MyComponent
访问MyDirective
的属性和方法,理想情况下,而不向上面的HTML添加任何内容。
答案 0 :(得分:24)
你可以注射它
class MyDirective {
constructor(private host:MyComponent) {}
严重的限制是,您需要事先知道组件的类型。
另见https://github.com/angular/angular/issues/8277
它还为您提前知道类型提供了一些解决方法。
答案 1 :(得分:8)
您的指令可以是可应用于任何组件的通用指令。所以,在这种情况下,在构造函数中注入组件是不可能的,所以这是另一种方法来做同样的事情
在构造函数中注入ViewContainerRef
constructor(private _viewContainerRef: ViewContainerRef) { }
然后使用
获取它let hostComponent = this._viewContainerRef["_data"].componentView.component;
答案 2 :(得分:6)
这取自github问题,就像魅力一样。缺点是需要事先了解组件,但在您的情况下,您需要知道您正在使用的方法。
import { Host, Self, Optional } from '@angular/core';
constructor(
@Host() @Self() @Optional() public hostCheckboxComponent : MdlCheckboxComponent
,@Host() @Self() @Optional() public hostSliderComponent : MdlSliderComponent){
if(this.hostCheckboxComponent) {
console.log("host is a checkbox");
} else if(this.hostSliderComponent) {
console.log("host is a slider");
}
}
信用: https://github.com/angular/angular/issues/8277#issuecomment-323678013
答案 3 :(得分:1)
如果要在自定义组件上使用attribute指令,则可以使这些组件从抽象类扩展,并将'forwardRef'抽象类类型扩展为您的组件类型。这样,您可以在抽象类中(在您的指令内)选择angular的DI。
抽象类:
export abstract class MyReference {
// can be empty if you only want to use it as a reference for DI
}
自定义组件:
@Component({
// ...
providers: [
{provide: MyReference, useExisting: forwardRef(() => MyCustomComponent)}
],
})
export class MyCustomComponent extends MyReference implements OnInit {
// ...
}
指令:
@Directive({
selector: '[appMyDirective]'
})
export class CustomDirective{
constructor(private host:MyReference) {
console.log(this.host);
// no accessing private properties of viewContainerRef to see here... :-)
}
}
这样,您可以在扩展抽象类的任何组件上使用指令。
这当然只会在您自己的组件上起作用。
答案 4 :(得分:1)
您可以使用 ViewContainerRef 访问宿主组件。
constructor(private el: ViewContainerRef) {}
ngOnInit() {
const _component = this.el && this.el.injector && this.el.injector.get(MyComponent);
}
答案 5 :(得分:1)
使指令通用的一种可能的解决方法是将组件的模板引用作为@Input 传递给指令。这增加了一点额外的 html,但它比我尝试过的许多其他 hack 效果更好。
@Directive({selector: '[myDirective]'})
export class MyDirective implements OnInit {
@Input() componentRef: any;
@Input() propName: string;
ngOnInit(){
if (this.componentRef != null) {
// Access component properties
this.componentRef[this.propName];
}
}
}
视图中的用法:
<!-- Pass component ref and the property name from component as inputs -->
<app-component #appComponentRef myDirective [componentRef]="appComponentRef" [propName]="'somePropInComponent'" .... >
也适用于其他指令。使用 @Directive
装饰器的 exportAs 属性获取对指令实例的引用。
<form #myForm="ngForm" myDirective [componentRef]="myForm" [propName]="'ngSubmit'" ....>
答案 6 :(得分:0)
我喜欢这样,它可以在Angular 9上使用。
export class FromItemComponentBase {
constructor(private hostElement: ElementRef) {
hostElement.nativeElement.__component=this;
}
}
@Component({
selector: 'input-error',
templateUrl: 'component.html'
})
export class FromItemErrorComponent extends FromItemComponentBase {
constructor(private hostElement: ElementRef) {
super(hostElement);
}
}
@Component({
selector: 'input-password',
templateUrl: 'component.html'
})
export class FromItemPasswordComponent extends FromItemComponentBase {
constructor(private hostElement: ElementRef) {
super(hostElement);
}
}
@Directive({selector: 'input-error,input-password,input-text'})
export class FormInputDirective {
component:FromItemComponentBase;
constructor(private hostElement: ElementRef) {
this.component=hostElement.nativeElement.__component;
}
}
答案 7 :(得分:0)
注意:这很笨拙,可能在 Angular 的未来版本中不起作用。 在 Angular 10 中,我能够像这样访问主机组件:
与@Sunil Garg 的解决方案类似,在指令的 ctor 中注入 ViewContainerRef
:
constructor(_viewContainerRef: ViewContainerRef)
像这样获取宿主组件:
let hostComponent = (<any>_viewContainerRef)._lContainer[0][8];
答案 8 :(得分:-1)
constructor(private vcRef: ViewContainerRef){
let parentComponent=(<any>this.vcRef)._view.context;
}