Угловое событие изменения QueryList ExpressionChangedAfterItHasBeenCheckedError - PullRequest
0 голосов
/ 15 июня 2019

При подписке на события изменения QueryList, а также при реагировании на событие и изменении свойства, с которым связано представление. Я получаю ExpressionChangedAfterItHasBeenCheckedError, и значение похоже на старое значение.

Я сделал стекблиц пример показывать ошибку.

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

Спасибо

1 Ответ

2 голосов
/ 15 июня 2019

вот что происходит;

в режиме разработки происходят два последовательных цикла CD, как объяснено в Соответствующие операции обнаружения изменений раздел этой статьи;

Работающее приложение Angular - это дерево компонентов. Во время обнаружения изменений Angular выполняет проверки для каждого компонента, который состоит из следующих операций, выполняемых в указанном порядке:

  1. обновить связанные свойства для всех дочерних компонентов / директив
  2. вызовите перехватчики жизненного цикла ngOnInit, OnChanges и ngDoCheck для всех дочерних компонентов / директив
  3. обновить DOM для текущего компонента
  4. запуск обнаружения изменений для дочернего компонента
  5. вызывать хук жизненного цикла ngAfterViewInit для всех дочерних компонентов / директив
  • после нажатия кнопки добавления, когда завершается обратный вызов, выполняется обнаружение изменений. comp имеет 1 элемент
  • во время первого цикла CD; DOM обновляется на шаге 3. элементы в comp добавляются в DOM, а {{ count.length }} проецируется в DOM как 0
  • @ViewChildren('comp') test: QueryList<ElementRef> обновляется непосредственно перед шагом 5. test: QueryList имеет 1 элемент
  • QueryList.changes наблюдаемый издает одновременно с запросом ViewChildren, непосредственно перед выполнением шага 5. this.count.push(this.test.length) выполняется и count.length становится 1.
  • ngAfterViewChecked выполняется, и первый CD (соответствующая часть нашего расследования) заканчивается
  • Начинается второй цикл CD. во время этого цикла угловая проверка предыдущих значений 1-го цикла CD с текущими значениями.
  • Во время этой проверки он обнаружил, что {{ count.length }} было спроецировано на DOM как 0, но теперь count.length равно 1. В этот момент выдается исключение.

Чтобы объяснить больше; изменение {{ count.length }} на {{ count }} не выдает ошибку, потому что ссылка на объект не изменилась.

* * Аналогично одна тысяча пятьдесят шесть; изменение {{ count.length }} на {{ comps.length }} также не выдает ошибку, поскольку comps.length также было равно 1 до начала 1-го цикла CD.

Я также создал демонстрационную версию, которая печатает соответствующие шаги в течение жизненного цикла компонента, связанные с нашим исследованием. Вы можете видеть, что исключение выдается до начала 4-го цикла CD. (1-й и 2-й циклы CD происходят до нажатия кнопки, поэтому в демонстрации следует соблюдать 3-й и 4-й циклы CD) Также обратите внимание на точку, где QueryList.changes испускает значение.

https://stackblitz.com/edit/angular-tmcttm

Наконец, как вы сказали, решение этой конкретной проблемы заключается в добавлении микрозадачи в очередь путем изменения этой строки

this.count.push(this.test.length);

в это

setTimeout(_ => this.count.push(this.test.length));

...