Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access host component from directive?

Say I have the following markup:

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

Is there any way I can access the component instance from the directive?

More specifically I want to be able to access the properties and methods of MyComponent from MyDirective, ideally without adding anything to the HTML above.

like image 989
AngularChef Avatar asked Sep 02 '17 14:09

AngularChef


People also ask

How do you use directive components?

To create a custom directive we have to replace @Component decorator with @Directive decorator. So, let's get started with creating our first Custom Attribute directive. In this directive, we are going to highlight the selected DOM element by setting an element's background color. Create an app-highlight.

Can we use component as directive?

Using @Component, we can create our HTML template which can be injected into the DOM at run time. To wrap it up, use @Directive to create a custom directive that can be used to modify the element or structure of the DOM. And use @Component, if you want to create the reusable UI components with custom behavior.

What is host in directive?

The host property, as mentioned in the documentation. Maps class properties to host element bindings for properties, attributes, and events, using a set of key-value pairs. where the host element is the element/component you have attached your directive to.

Can we use component as directive in Angular?

by putting brackets around the selector, that informs Angular of how it can be used. in this case [nbMenuItem] means this can be use as an attribute of a DOM element, and as such as an directive. Nailed the answer!


3 Answers

You can just inject it

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

A severe limitation is, that you need to know the type of the component in advance.

See also https://github.com/angular/angular/issues/8277
It also provides some workarounds for when you don't know the type in advance.

like image 159
Günter Zöchbauer Avatar answered Oct 18 '22 02:10

Günter Zöchbauer


Your directive could be the generic one that can be applied to any of your components. So, in that case, injecting the component in constructor would not be possible, So here is one other way to do the same

Inject the ViewContainerRef in constructor

constructor(private _viewContainerRef: ViewContainerRef) { }

and then get it using

let hostComponent = this._viewContainerRef["_data"].componentView.component;
like image 22
Sunil Garg Avatar answered Oct 18 '22 01:10

Sunil Garg


If you want to use the attribute directive on your custom components you could have those components extend from an abstract class and 'forwardRef' the abstract class type to your component type. This way you can make angular's DI select on the abstract class (within your directive).

Abstract class:

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

Custom Component:

@Component({
  // ...
  providers: [
    {provide: MyReference, useExisting: forwardRef(() => MyCustomComponent)}
  ],
})
export class MyCustomComponent extends MyReference implements OnInit {
// ...
}

Directive:

@Directive({
  selector: '[appMyDirective]'
})
export class CustomDirective{

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

}

This way you can use the directive on any component that extends your abstract class.

This will of course only work on your own components.

like image 23
Michiel Windey Avatar answered Oct 18 '22 03:10

Michiel Windey