16

I have a component with the name EasyBoxComponent, and a @Directive with this @Viewchild:

@ViewChild(EasyBoxComponent) myComponent: EasyBoxComponent;

I thought this was the correct syntax, but this.myComponent is always undefined.


Here's the whole code:

<my-easybox></my-easybox>
<p myEasyBox data-href="URL">My Directive</p>
import { Directive, AfterViewInit, HostListener, ContentChild } from '@angular/core';
import { EasyBoxComponent } from '../_components/easybox.component';

@Directive({
  selector: '[myEasyBox]'
})
export class EasyBoxDirective implements AfterViewInit {

  @ContentChild(EasyBoxComponent) myComponent: EasyBoxComponent;
  @ContentChild(EasyBoxComponent) allMyCustomDirectives;

  constructor() {
  }

  ngAfterViewInit() {
    console.log('ViewChild');
    console.log(this.myComponent);
  }

  @HostListener('click', ['$event'])
  onClick(e) {
    console.log(e);
    console.log(e.altKey);
    console.log(this.myComponent);
    console.log(this.allMyCustomDirectives);
  }
}
Nicke Manarin
  • 3,026
  • 4
  • 37
  • 79
Michalis
  • 6,686
  • 13
  • 52
  • 78
  • where you definer `myComponent` ? – Pardeep Jain Apr 07 '17 at 06:46
  • A directive doesn't have a view, therefore `@ViewChild()` is pointless. Try `@ContentChild()` instead. If it doesn't work, please provide more code that demonstrates what you try to accomplish. – Günter Zöchbauer Apr 07 '17 at 06:48
  • 1
    You can't use `ContentChild()` or `@ViewChild()` to query something outside of the component. Only projected content (as the text `MyDirective` is) or direct children within a components view. `` is a sibling to the element that has the directive. Angular doesn't provide a way to query it. You can use `querySelector` but there are probably better ways. But I would need to understand the actual problem you're trying to solve better to be able to make suggestions. – Günter Zöchbauer Apr 07 '17 at 07:36
  • I want to make a componet that opens images.... And a directive to add to every image. Every time i click to an image (directive)... I want to send the src to the component to open it – Michalis Apr 07 '17 at 07:38
  • I will make my component communicate with the directive through service – Michalis Apr 07 '17 at 09:15

2 Answers2

17

ContentChild works with the AfterContentInit interface, so the template should be like:

<p myEasyBox data-href="URL">
   <my-easybox></my-easybox>
</p>

and the @Directive:

@Directive({
  selector: '[myEasyBox]'
})
export class EasyBoxDirective implements AfterContentInit {
  @ContentChild(EasyBoxComponent) myComponent: EasyBoxComponent;
  @ContentChild(EasyBoxComponent) allMyCustomDirectives;
    
  ngAfterContentInit(): void {
    console.log('ngAfterContentInit');
    console.log(this.myComponent);
  }
    
  constructor() {
  }
    
  @HostListener('click', ['$event'])
  onClick(e) {
    console.log(e);
    console.log(e.altKey);
    console.log(this.myComponent);
    console.log(this.allMyCustomDirectives);
  }
}
Nicke Manarin
  • 3,026
  • 4
  • 37
  • 79
Julia Passynkova
  • 17,256
  • 6
  • 33
  • 32
1

Since the component is not the child of the directive, the child selector will not work.

Instead, use references:

<my-easybox #myBox></my-easybox>
<p [myEasyBox]="myBox" data-href="URL">My Directive</p>
@Input('myEasyBox') myComponent: EasyBoxComponent;
Nicke Manarin
  • 3,026
  • 4
  • 37
  • 79
forivall
  • 9,504
  • 2
  • 33
  • 58