Get reference to a directive used in a component

AngularAngular2 DirectivesAngular Template

Angular Problem Overview


I have a component whose template looks something like this:

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

I need access to the MyCustomDirective class instance used here. When I want to get access to a child component, I use a ViewChild query.

Is there an equivalent feature to get access to a child directive?

Angular Solutions


Solution 1 - Angular

You can use exportAs property of the @Directive annotation. It exports the directive to be used in the parent view. From the parent view, you can bind it to a view variable and access it from the parent class using @ViewChild().

Example With a 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');
  }
}

Update

As mentioned in the comments, there is another alternative to the above approach.

Instead of using exportAs, one could directly use @ViewChild(MyCustomDirective) or @ViewChildren(MyCustomDirective)

Here is some code to demonstrate the difference between the three approaches:

@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
  
}

Update

Another plunker with more clarification

Solution 2 - Angular

It appears that since @Abdulrahman's answer, directives can no longer be accessed from @ViewChild or @ViewChildren as these pass only items on the DOM element itself.

Instead, you must access directives using @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
}

There is also no longer a directives property on @Component attribute.

Solution 3 - Angular

The sole remaining solution since 2019

As mentioned in the comments of the other answers, these other (previously valid) methods would not work with the more recent versions of Angular.


Rejoice, however, for there is an even simpler way to get it injected: directly from the constructor!

@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!
  }
}

Additionally, you can add multiple annotations to tell the Dependency Injection engine where to look for the content to inject, using @Self or @Optional for example 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBen DiltsView Question on Stackoverflow
Solution 1 - AngularAbdulrahman AlsoghayerView Answer on Stackoverflow
Solution 2 - AngularTobias JView Answer on Stackoverflow
Solution 3 - AngularccjmneView Answer on Stackoverflow