#local variable внутри *ngIf

На локальную переменную шаблона (#myVar) можно ссылаться только внутри блока шаблона (<template>). В случае когда необходимо сослаться извне, ссылка будет пустой. Это немного неочевидно при использовании структурных директив, таких как *ngIf.s

<div *ngIf="true">
  <p class="inside" #p> Feature </p>
  <p>Class: "{{ p?.className }}"</p> <!-- Вот тут работает -->
</div>

<p>Class: "{{ p?.className }}"</p>   <!-- А здесь не работает -->

Есть 2 варианта решения

@ViewChild

Используетмя декоратор @ViewChild с сеттером. Он будет запускаться каждый раз, когда изменяется ngIf.

export class AppComponent {

  ref: ElementRef; // В шаблоне Class: "{{ ref?.nativeElement.className }}"

  constructor(private cdr: ChangeDetectorRef) {}

  @ViewChild('p') 
  set paragraph(e: ElementRef) {
    this.ref = e;
    // ExpressionChangedAfterItHasBeenCheckedError
    this.cdr.detectChanges();
  }

}

@ViewChildren

Используется декортор @ViewChildren. Он даёт QueryList (а-ля SelectorAll), на который следует подписаться. Список будет обновляться при каждом изменении переменной template (ngIf включается или выключается).

export class AppComponent implements AfterViewInit, OnDestroy {

  ref: ElementRef; // В шаблоне Class: "{{ ref?.nativeElement.className }}"

  constructor(private cdr: ChangeDetectorRef) {}

  @ViewChildren('p') 
  pQueryList: QueryList<ElementRef>;
  /** destroy subject (pattern) */
  private _destroy$ = new Subject<void>();  

  ngAfterViewInit(): void {
    this.processChanges();
    this.pQueryList.changes.pipe(
      takeUntil(this._destroy$)
    ).subscribe(() => this.processChanges());
  }

  processChanges(): void {
    this.ref = this.pQueryList.first;
    this.cdr.detectChanges();   
  }

  ngOnDestroy(): void {
    this._destroy$.next();
    this._destroy$.complete();
  }

}

Demo


Похожие записи

Как добавить ng-bootstrap компоненты в проект Angular-CLI?

Покажу на примере нового проекта.

ng new project_name
cd project_name
npm install --save bootstrap@next
npm install --save @ng-bootstrap/ng-bootstrap

В angular-cli.json в секцию style надо добавить наш CSS, чтобы глобально подключить стили.

  "styles": [
    "styles.css",
    "../node_modules/bootstrap/dist/css/bootstrap.min.css"
  ],
17 августа 2017 г. в Angular

@Directive v/s @Component in Angular

Компоненты создают DOM элементы и добавляют к ним поведение, а директивы только добавляют поведение к существующим DOM элементам

13 августа 2018 г. в Angular

Angular dependency injection

Определение Provider (useClass, useValue, useFactory ), Injector. Декоратор @Inject, ключ multi: true

13 ноября 2018 г. в Angular