Angular 2:获取对组件中使用的指令的引用

Ben*_*lts 58 angular-template angular2-directives angular

我有一个组件,其模板看起来像这样:

<div [my-custom-directive]>Some content here</div>
Run Code Online (Sandbox Code Playgroud)

我需要访问此处使用的MyCustomDirective类实例.当我想要访问子组件时,我使用ng.core.ViewChild查询.是否有相同的功能来访问子指令?

Abd*_*yer 93

您可以使用注释的exportAs属性@Directive.它导出要在父视图中使用的指令.在父视图中,您可以将其绑定到视图变量并使用父类访问它@ViewChild().

示例使用plunker:

@Directive({
  selector:'[my-custom-directive]',
  exportAs:'customdirective'   //the name of the variable to access the directive
})
class MyCustomDirective{
  logSomething(text){
    console.log('from custom directive:', text);
  }
}

@Component({
    selector: 'my-app',
    directives:[MyCustomDirective],
    template: `
    <h1>My First Angular 2 App</h1>

    <div #cdire=customdirective my-custom-directive>Some content here</div>
    `
})
export class AppComponent{
  @ViewChild('cdire') element;

  ngAfterViewInit(){
    this.element.logSomething('text from AppComponent');
  }
}
Run Code Online (Sandbox Code Playgroud)

更新

正如评论中所提到的,上述方法还有另一种选择.

exportAs可以直接使用@ViewChild(MyCustomDirective)或代替使用@ViewChildren(MyCustomDirective)

以下是一些代码,用于演示三种方法之间的区别:

@Component({
    selector: 'my-app',
    directives:[MyCustomDirective],
    template: `
    <h1>My First Angular 2 App</h1>

    <div my-custom-directive>First</div>
    <div #cdire=customdirective my-custom-directive>Second</div>
    <div my-custom-directive>Third</div>
    `
})
export class AppComponent{
  @ViewChild('cdire') secondMyCustomDirective; // Second
  @ViewChildren(MyCustomDirective) allMyCustomDirectives; //['First','Second','Third']
  @ViewChild(MyCustomDirective) firstMyCustomDirective; // First

}
Run Code Online (Sandbox Code Playgroud)

更新

另一个有更多澄清的吸油烟机

  • 答案很棒.但这也可以在没有`cdire`的情况下直接完成,如`@ViewChild(MyCustomDirective)元素:MyCustomDirective;`然后,在`ngAfterViewInit - this.element.logSomething('text from ...')`.那么为什么你的方法直接通过传递类型你可以这样做?只是为了澄清. (9认同)
  • @micronyks你的方法很好.但是,它假设只有一个"MyCustomDirective".如果有多个指令,它将与第一个指令匹配.但是,当使用`exportAs`时,您可以特别指定任何一个,例如,第二个`MyCustomDirective`. (7认同)
  • 另一种选择是使用ViewChild中的{read:SomeType}参数,如下所述:http://stackoverflow.com/a/37476195/1736032.例如:`@ ViewChild('cdire',{read:MyCustomDirective})secondMyCustomDirective:MyCustomDirective`和`<div #cdire my-custom-directive> Second </ div>`(不需要exportAs). (5认同)
  • 如果模板包含多个原本匹配的模板,则使用模板变量可以更轻松地指出单个元素.它总是取决于你实际想要完成什么以及你的情况.如果你想得到所有,那么你也会使用`@ViewChildren()` (2认同)

Tob*_*s J 16

看来,自@ Abdulrahman的答案以来,无法再访问指令,@ViewChild或者@ViewChildren因为这些指令只传递DOM元素本身的项目.

相反,您必须使用@ContentChild/ 访问指令@ContentChildren.

@Component({
    selector: 'my-app',
    template: `
    <h1>My First Angular 2 App</h1>

    <div my-custom-directive>First</div>
    <div #cdire=customdirective my-custom-directive>Second</div>
    <div my-custom-directive>Third</div>
    `
})
export class AppComponent{
  @ContentChild('cdire') secondMyCustomDirective; // Second
  @ContentChildren(MyCustomDirective) allMyCustomDirectives; //['First','Second','Third']
  @ContentChild(MyCustomDirective) firstMyCustomDirective; // First
}
Run Code Online (Sandbox Code Playgroud)

directives属性上也不再有@Component属性.

  • 使用@ContentChild创建的实例未定义.为什么?例如,在组件函数`this.firstMyCustomDirective`中是`undefined` (5认同)
  • /sf/ask/2402872181/我认为存在一些误解. (3认同)
  • ContentChild或ViewChild似乎不起作用并返回未定义的变量 (2认同)
  • 截至2019年,这似乎不正确,ContentChild和ViewChild似乎都在ngAfterViewInit中返回未定义 (2认同)

ccj*_*mne 16

自 2019 年以来唯一剩余的解决方案

正如其他答案的评论中所述,这些其他(以前有效)方法不适用于较新版本的 Angular。


然而,庆幸的是,有一种更简单的方法来注入它:直接从构造函数中注入!

@Component({
   // ...
})
export class MyComponent implements OnInit {

  // Would be *undefined*
  // @ContentChild(MyDirective, { static: true })
  // private directive: MyDirective;

  constructor(private directive: MyDirective) { }

  ngOnInit(): void {
    assert.notEqual(this.directive, null); // it passes!
  }
}
Run Code Online (Sandbox Code Playgroud)

此外,您可以添加多个注释来告诉依赖注入引擎在哪里查找要注入的内容,例如使用@Self@Optional

  • 我对这种方法有疑问,似乎 DI 注入了新创建的指令实例,而不是我的组件中使用的指令实例,因此尽管指令实例不为空,但大多数属性未初始化(我做了一个实验,添加 ' instanceId' 字段,它与我的组件中的不一样) (2认同)