Почему @ViewChild все еще не определен, хотя для * ngIf установлено значение true - PullRequest
3 голосов
/ 05 августа 2020

Я столкнулся со следующей проблемой, которая была исправлена ​​свойством {static: false} в @ViewChild. Этот Q / A stackoverflow помог с этим Как мне использовать новую опцию stati c для @ViewChild в Angular 8? .

Я хотел лучше понять этот сценарий и как static изменяет результат, а также то, как обнаружение изменений влияет на этот сценарий. Я прочитал об обнаружении изменений в документации angular и обнаружил, что этого крайне не хватает.

Я придумал stackblitz, который иллюстрирует то, чего я не понимаю. Stackblitz angular пример

При двойном нажатии кнопки toggle в командной строке появляется следующее:

> undefined undefined
> undefined undefined
> undefined ElementRef {nativeElement: div}
> undefined ElementRef {nativeElement: div}

Однако Я ожидаю:

> undefined undefined
> undefined ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}
> ElementRef {nativeElement: div} ElementRef {nativeElement: div}

Вот лог c для кода - (см. Полный код в stackblitz)

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  @ViewChild("contentPlaceholder", { static: true })
  trueViewChild: ElementRef;

  @ViewChild("contentPlaceholder", { static: false })
  falseViewChild: ElementRef;

  display = false;

  constructor() {}

  show() {
    console.log(this.trueViewChild, this.falseViewChild);
    this.display = true;
    console.log(this.trueViewChild, this.falseViewChild);
  } 
}

Мои вопросы:

  1. Почему значение второй строки this.falseViewChild отображается как неопределенное. Не должно ли обнаружение изменений запускаться после установки this.display = false, и поэтому оно не должно быть неопределенным?
  2. Почему this.trueViewChild остается неопределенным. Я ожидал, что он найдет элемент после того, как *ngIf станет истинным?

1 Ответ

1 голос
/ 05 августа 2020

Angular обнаружения изменений работает с помощью библиотеки zone. js. Обновление запросов ViewChild / Content происходит во время цикла обнаружения изменений .

Зона. js библиотека исправляет асинхронные c API (addEventListener, setTimeout (), Promises ...) и знает какая именно задача выполняется и когда она завершена.

Например, он может прослушивать событие щелчка и выдавать уведомление, когда эта задача была завершена (нет ожидающих задач, то есть эта зона становится стабильным).

Angular подписывается на эти уведомления, чтобы выполнить обнаружение изменений во всех трех компонентах, начиная с root компонента.

// your code 
(click)="someHandler()" 

someHandler() {              
 ....
}

// angular core
checkStable() {
  if (there is no any task being executed and there is no any async pending request) {
    PERFORM CHANGE DETECTION
  } 
}

Порядок в коде примерно следующий:

 click
  ||
  \/
someHandler()
  ||
  \/
checkStable()
  ||
  \/
PERFORM CHANGE DETECTION

Итак, давайте ответим на ваши вопросы:

  1. Почему значение второй строки this.falseViewChild отображается как неопределенное . Не должно ли обнаружение изменений запускаться после установки this.display = false, и, следовательно, оно не должно быть неопределенным?

При изменении display свойства

* 1029 реактивность отсутствует. *

Вот почему вы получаете следующий результат при первом щелчке:

> undefined undefined
> undefined undefined   <---- nothing has updated

 ......
 update happens here

Он будет обновлен позже, но вы не увидите его, если не нажмете еще раз, потому что вы не регистрируете их значения позже.

Why does this.trueViewChild stay undefined. I would expect it to find the element after the *ngIf becomes true?

Потому что для этого есть правило из Angular документации :

С запросами stati c ( stati c: true), запрос разрешается после создания представления, но до запуска обнаружения изменений. Результат, однако, никогда не будет обновлен , чтобы отразить изменения в вашем представлении, такие как изменения в блоках ngIf и ngFor.

Это означает, что если это изначально false (например, внутри * ngIf или ng-template), тогда всегда будет false

...