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

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

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

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

41
AngularChef 2 Сен 2017 в 17:25

7 ответов

Лучший ответ

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

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

Серьезным ограничением является то, что вам необходимо заранее знать тип компонента.

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

48
Günter Zöchbauer 2 Сен 2017 в 14:27

Мой обходной путь для динамических типов

Проверено на Angular 9.1

    public GetComponent(): any {
        const container = this._viewContainerRef["_lContainer"][0];
        if (container instanceof HTMLElement) {
            return container;
        }

        let containerName = container.constructor.name;
        let componentName = containerName.split("_")[1];
        return container.filter((x: any) => x && x.constructor.name == componentName)[0];
    }

Редактировать: Работа только в отладочной сборке

0
CorrM 4 Июл 2020 в 13:06

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

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

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... :-)
  }

}

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

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

10
Michiel Windey 11 Янв 2019 в 08:58

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

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

constructor(private _viewContainerRef: ViewContainerRef) { }

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

let hostComponent = this._viewContainerRef["_data"].componentView.component;
15
Sunil Garg 1 Фев 2018 в 13:31

Мне так нравится, он работает на Angular 9.

export class FromItemComponentBase  {
  constructor(private hostElement: ElementRef) {
    hostElement.nativeElement.__component=this;
  }
}

@Component({
  selector: 'input-error',
  templateUrl: 'component.html'
})
export class FromItemErrorComponent extends FromItemComponentBase {
  constructor(private hostElement: ElementRef) {
    super(hostElement);
  }
}

@Component({
  selector: 'input-password',
  templateUrl: 'component.html'
})
export class FromItemPasswordComponent extends FromItemComponentBase {
  constructor(private hostElement: ElementRef) {
    super(hostElement);
  }
}

@Directive({selector: 'input-error,input-password,input-text'})
export class FormInputDirective {
  component:FromItemComponentBase;

  constructor(private hostElement: ElementRef) {
    this.component=hostElement.nativeElement.__component;
  }
}
0
shine 19 Апр 2020 в 00:16

Это взято из проблемы 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

8
Anthony 24 Апр 2018 в 13:37
constructor(private vcRef: ViewContainerRef){
        let parentComponent=(<any>this.vcRef)._view.context;
}
0
Akshay Bohra 22 Июн 2018 в 19:43