关于angular:如何从指令访问主机组件?

How to access host component from directive?

假设我有以下标记:

1
<my-comp myDirective></my-comp>

我是否可以从该指令访问组件实例?

更具体地说,我希望能够从MyDirective中访问MyComponent的属性和方法,理想情况下不需要向上述HTML中添加任何内容。


你可以直接注射

1
2
class MyDirective {
  constructor(private host:MyComponent) {}

一个严重的限制是,您需要提前知道组件的类型。

另请参见https://github.com/angular/angular/issues/8277它还提供了一些解决办法,当您不知道预先类型。


您的指令可以是可应用于任何组件的通用指令。因此,在这种情况下,在构造函数中注入组件是不可能的,所以这里有另外一种方法来实现同样的目的。

在构造函数中注入EDOCX1[0]

1
constructor(private _viewContainerRef: ViewContainerRef) { }

然后用

1
let hostComponent = this._viewContainerRef["_data"].componentView.component;


这是从Github发行版中提取的,工作起来很有魅力。缺点是需要事先知道组件,但在您的情况下,您仍然需要知道正在使用的方法。

1
2
3
4
5
6
7
8
9
10
11
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问题注释-323678103


如果要对自定义组件使用attribute指令,可以将这些组件从抽象类和"forwardRef"抽象类类型扩展到组件类型。这样,您就可以在抽象类(在您的指令中)上进行Angular的DI选择。

抽象类:

1
2
3
export abstract class MyReference {
  // can be empty if you only want to use it as a reference for DI
}

自定义组件:

1
2
3
4
5
6
7
8
9
@Component({
  // ...
  providers: [
    {provide: MyReference, useExisting: forwardRef(() => MyCustomComponent)}
  ],
})
export class MyCustomComponent extends MyReference implements OnInit {
// ...
}

指令:

1
2
3
4
5
6
7
8
9
10
11
@Directive({
  selector: '[appMyDirective]'
})
export class CustomDirective{

  constructor(private host:MyReference) {
    console.log(this.host);
    // no accessing private properties of viewContainerRef to see here... :-)
  }

}

这样就可以对扩展抽象类的任何组件使用该指令。

当然,这只能在您自己的组件上工作。


1
2
3
constructor(private vcRef: ViewContainerRef){
        let parentComponent=(this.vcRef)._view.context;
}