Angular6 @ViewChild не определен с помощью ngIf

#angular #viewchild

#angular #viewchild

Вопрос:

У меня проблема с использованием @ViewChild с компонентом, отображаемым через ngIf. Я нашел различные решения, но ни одно из них не пригодилось для меня. Это мой основной компонент, состоящий из различных шагов (я показал только 2 в коде для краткости) с кнопкой для прямой навигации и кнопкой для сброса возврата компонента на первом шаге. Первый шаг показан при открытии страницы:

 ...
<div class="my-container">
    <first-child *ngIf="showFirtChild"></first-child>
    <second-child *ngIf="showSecondChild"></second-child>
</div>
<button (click)="goToNextStep()"></button>
<button (click)="reset()"></button>
...
  
 export class MainComponent implements OnInit {
    @ViewChild(FirstChild) private firstChildComp: MyFirstChildComponent;
    showFirtChild: boolean = true;

    ngOnInit() {
        //here firstChildComp is defined
    }

    //code for navigate through steps
    reset() {
        this.showFirtChild= true;
        this.firstChildComp.fillTable(); //fillTable is a function defined in MyFirstChildComponent
    }
...
}
  

Во время навигации по шагам ссылка на firstChildComp теряется, а при вызове reset() результат childComp не определен. Я знаю, что причиной является ngIf, поэтому я попытался использовать ngAfterViewInit:

 ngAfterViewInit() {
    this.fcomp = this.firstChildComp;
}

reset() {
        this.showFirtChild= true;
        this.fcomp .fillTable();
}
  

но это не решает мою проблему.
Есть предложения?

Комментарии:

1. На ngAfterViewInit этапе вы можете получить подкомпоненты. Является fillTable ли метод закрытым?

2. Ни один метод не является общедоступным

Ответ №1:

Как говорится в документе Angular:

«Значение True для разрешения результатов запроса до запуска обнаружения изменений. Если какие-либо результаты запроса находятся внутри вложенного представления (например, *ngIf), запрос разрешается после запуска обнаружения изменений «.

Итак, передача параметра { static: false } в @ViewChild решает проблему, поскольку доступ к нему осуществляется через ngAfterViewInit, вместо этого доступ к on осуществляется { static: true } до запуска обнаружения изменений so в ngOnInit.

Комментарии:

1. статическая опция доступна только с версии 8 (согласно Angular docs)

Ответ №2:

ngIf удалит ваш компонент из DOM. Таким образом, он становится неопределенным. Если вы используете [hidden]="!showFirstChild" вместо этого, он будет только скрыт и будет доступен в компоненте.

Вот stackblitz, где вы можете это проверить.

Комментарии:

1. Использование hidden работает правильно, но я предпочитаю использовать пользовательский ngIf, потому что я передаю данные через различные этапы.

2. Хм, тогда я думаю, что решение dince12 идеально.

Ответ №3:

Попробуйте запустить обнаружение изменений между ними, чтобы убедиться, что шаблон DOM считывает DOM после изменения в reset.

В шаблоне:

 <first-child #firstChild *ngIf="showFirtChild"></first-child>
  

В контроллере:

 import { ChangeDetectorRef } from '@angular/core';

export class exampleClass implements 
{

  @ViewChild('firstChild') public firstChildComp: MyFirstChildComponent;
  public fcomp: any;
  public showFirtChild: boolean;

  constructor(private ref: ChangeDetectorRef,
            //your services) {}

  public ngAfterViewInit() 
  {
      this.showFirtChild = true;
      this.ref.detectChanges();

      this.fcomp = this.firstChildComp;
  }

  public reset(): void 
  {
      this.fcomp.fillTable();
  }
}
  

Документация ChangeDetectorRef для дальнейшего чтения.

Комментарии:

1. извините, проверьте редактирование, должно быть хорошо. Если это не работает, пожалуйста, объясните, что не происходит, или какие-либо ошибки.

2. При вашем редактировании fcomp в reset() правильно определен, но ничего не меняется. Это очень странно, похоже, что выполняется fillTable(), фактически никаких ошибок не появляется, но он ничего не делает… Используя отладчик, я вижу, что fcomp верен, и инструкция выполнена, но таблица не заполнена…

3. Итак, вы разобрались с проблемами ViewChild? Не уверен, что я могу помочь с правильным заполнением таблицы. Поместите console.log(); в fillTable(); и если вы видите это, значит, есть проблема с функцией.

4. Это не проблема таблицы, потому что выполняется каждый другой метод MyFirstChildComponent, но на самом деле он ничего не делает.

5. Итак, если бы в MyFirstChildComponent вы запустили this.fillTable(), это сработало бы?

Ответ №4:

Если вы все еще ищете ответ, вы также можете попробовать установить значение статического флага на true . Это приведет к viewContainerRef загрузке дочернего компонента в зависимости от ngIf значения.