Как получить доступ к компоненту хоста из директивы?

Скажем, у меня есть следующая разметка:

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

Есть ли способ получить доступ к экземпляру компонента из директивы?

В частности, я хочу иметь доступ к свойствам и методам MyComponent из MyDirective, идеально , не добавляя ничего в HTML выше.

Ответ 1

Вы можете просто ввести его

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

Суровое ограничение состоит в том, что вам нужно заранее знать тип компонента.

См. также https://github.com/angular/angular/issues/8277
Он также предоставляет некоторые обходные пути, когда вы заранее не знаете тип.

Ответ 2

Это взято из проблемы GitHub и работает как шарм. Недостатком является то, что вам нужно знать компоненты заранее, но в вашем случае вам все равно придется знать методы, которые вы используете.

import { Host, Self, Optional } from '@angular/core';

    constructor(
         @Host() @Self() @Optional() public hostCheckboxComponent : MdlCheckboxComponent
        ,@Host() @Self() @Optional() public hostSliderComponent   : MdlSliderComponent){
                if(this.hostCheckboxComponent) {
                       console.log("host is a checkbox");
                } else if(this.hostSliderComponent) {
                       console.log("host is a slider");
                }
         }

Кредит: https://github.com/angular/angular/issues/8277#issuecomment-323678013

Ответ 3

Ваша директива может быть общей, которая может быть применена к любому из ваших компонентов. Таким образом, в этом случае инъекция компонента в конструкторе была бы невозможна. Итак, вот еще один способ сделать тот же

Вставить ViewContainerRef в конструктор

constructor(private _viewContainerRef: ViewContainerRef) { }

а затем получить его с помощью

let hostComponent = this._viewContainerRef["_data"].componentView.component;

Ответ 4

constructor(private vcRef: ViewContainerRef){
        let parentComponent=(<any>this.vcRef)._view.context;
}

Ответ 5

Если вы хотите использовать директиву атрибута в ваших пользовательских компонентах, вы можете сделать так, чтобы эти компоненты расширялись от абстрактного класса и 'forwardRef' - от абстрактного типа класса до типа вашего компонента. Таким образом, вы можете выбрать угловой DI для абстрактного класса (в вашей директиве).

Абстрактный класс:

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

Пользовательский компонент:

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

Директива:

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

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

}

Таким образом, вы можете использовать директиву для любого компонента, расширяющего ваш абстрактный класс.

Это, конечно, будет работать только на ваших собственных компонентах.