Как проверить, вступил ли ngIf

Что я делаю
У меня есть компонент, который скрывает/показывает с помощью *ngIf на основе простого булева. Когда компонент становится видимым, я хочу применить фокус к дочернему элементу внутри его шаблона.

Проблема
Если я переворачиваю логическое значение, компонент показывает правильно, но если я попытаюсь получить ссылку на дочерний элемент, используя this._elRef.nativeElement.querySelector("div#test"), он просто вернется null. Если я подожду несколько секунд, то тот же код вернет ссылку на элемент, как я ожидал.

Спекуляция
Я предполагаю, что после переброса Boolean angular проходит весь цикл рендеринга, чтобы показать вновь видимый компонент, и что это еще не закончилось к моменту, когда я применил querySelector() в следующей строке.

Что я хотел бы знать
Так что мне интересно, как я могу быть уверен, что мой ngIf вступил в силу, а элементы - в DOM, который нужно выбрать?
Есть ли такая вещь, как обратный вызов для ngIf или может Я заставляю представление обновлять и получать обратный вызов из этого?

Надеюсь, это имеет смысл. Это был долгий день (долгая неделя), и я очень устал.
Спасибо всем

Если это помогает, я использую Angular2 v2.0.0-beta.15

Ответ 1

Если вы переверните логическое значение до true и в следующей строке кода вы попытаетесь получить ссылку на элемент или элемент DOM, контролируемый NgIf... ну, этот компонент или элемент DOM еще не существует, Angular не работает параллельно с вашим кодом. Ваш обратный вызов JavaScript должен быть завершен, затем выполняется Angular (изменение обнаружения), которое будет замечать изменение логического значения и создать компонент или элемент DOM и вставить его в DOM.

Чтобы устранить проблему, вызовите setTimeout(callbackFn, 0) после того, как вы перевернули логическое значение. Это добавляет ваш callbackFn в очередь сообщений JavaScript. Это обеспечит выполнение Angular (обнаружение изменений) перед вашей функцией обратного вызова. Следовательно, когда ваш callbackFn выполняется, элемент, который вы хотите сфокусировать, должен теперь существовать. Использование setTimeout(..., 0) гарантирует, что ваш callbackFn будет вызван в следующем повороте цикла событий .

Эта методика использования setTimeout(..., 0) используется в путеводителе LifeCycle hooks dev при обсуждении AfterView * hooks.

Вот несколько других примеров, если вам нужна дополнительная информация:

Ответ 2

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

Метод setTimeout() является вполне жизнеспособным, но имеет существенный недостаток. Если вы просто установите класс для размещения элемента, как и я, вы получите неудобный результат, так как код выполняется после цикла angular.

Использование ChangeDetectorRef приводит к результату, который не прыгает.

Итак, вместо этого:

class Foo {
  public isDisplayed = false;

  constructor(@Inject(ElementRef) private elementRef: ElementRef) {
  }

  public someMethod(): void {
     this.isDisplayed = true;
     setTimeout(() => {
         const child = this.elementRef.nativeElement.querySelector('.child-element');
         // ...
     });
  }
}

Вы можете сделать это:

class Foo {
  public isDisplayed = false;

  constructor(@Inject(ElementRef) private elementRef: ElementRef,
              @Inject(ChangeDetectorRef) private changeDetectorRef: ChangeDetectorRef) {
  }

  public someMethod(): void {
     this.isDisplayed = true;
     this.changeDetectorRef.detectChanges();
     const child = this.elementRef.nativeElement.querySelector('.child-element');
     // ...
  }
}