【问题标题】:Get reference to a directive used in a component获取对组件中使用的指令的引用
【发布时间】:2016-07-20 15:04:20
【问题描述】:

我有一个组件,其模板如下所示:

<div [my-custom-directive]>Some content here</div>

我需要访问此处使用的MyCustomDirective 类实例。当我想访问子组件时,我使用ViewChild 查询。

是否有等效的功能可以访问子指令?

【问题讨论】:

    标签: angular angular2-directives angular-template


    【解决方案1】:

    您可以使用@Directive 注释的exportAs 属性。它导出要在父视图中使用的指令。在父视图中,您可以将其绑定到视图变量并使用 @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');
      }
    }
    

    更新

    如 cmets 中所述,上述方法还有另一种替代方法。

    不使用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
    
    }
    

    更新

    Another plunker with more clarification

    【讨论】:

    • 答案很好。但是这也可以不用cdire直接像@ViewChild(MyCustomDirective) element:MyCustomDirective;那样,在ngAfterViewInit - this.element.logSomething('text from...')。那么为什么你的方法直接通过你可以这样做的类型呢?只是为了澄清。
    • @micronyks 你的方法很好。但是,它假设只有一个MyCustomDirective。如果有多个指令,它将匹配第一个。但是,当使用exportAs 时,您可以特别指定任何一个,例如第二个MyCustomDirective
    • 如果您的模板包含多个本来可以匹配的元素,则使用模板变量可以更容易地指出一个元素。这始终取决于您实际尝试完成的工作以及您的情况。如果你想得到所有,那么你也可以使用@ViewChildren()
    • 我同意,但如果你有多个指令,你也可以传递适当的类型。你不能吗?
    • 另一种选择是使用 ViewChild 中的 {read: SomeType} 参数,如下所述:stackoverflow.com/a/37476195/1736032。例如:@ViewChild('cdire', {read:MyCustomDirective}) secondMyCustomDirective: MyCustomDirective&lt;div #cdire my-custom-directive&gt;Second&lt;/div&gt;(无需导出)。
    【解决方案2】:

    似乎自从@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
    }
    

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

    【讨论】:

    • 使用@ContentChild 创建的实例未定义。为什么 ?例如,在组件函数内部this.firstMyCustomDirectiveundefined
    • ContentChild 或 ViewChild 似乎不起作用并返回未定义的变量
    • 截至 2019 年,这似乎不正确,ContentChild 和 ViewChild 似乎都在 ngAfterViewInit 中返回 undefined
    【解决方案3】:

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

    正如其他答案的 cmets 中所述,这些其他(以前有效的)方法不适用于更新版本的 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!
      }
    }
    

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

    【讨论】:

    • 这样干净得多! fwiw 它Self() 是正确的方法,并且该值在构造函数中可用。 (womm)
    • 我对这种方法有疑问,似乎 DI 注入了新创建的指令实例,而不是那些在我的组件中使用的指令实例,因此尽管指令实例不是所描述的 null,但它的大部分属性都没有初始化(我做了一个实验,添加了“instanceId”字段,和我的组件中的不一样)
    猜你喜欢
    • 2019-01-14
    • 2023-04-06
    • 2020-03-31
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多