Мой компонент имеет стили, которые зависят от текущей даты и времени. В моем компоненте у меня есть следующая функция.
private fontColor( dto : Dto ) : string {
// date d'exécution du dto
let dtoDate : Date = new Date( dto.LastExecution );
(...)
let color = "hsl( " + hue + ", 80%, " + (maxLigness - lightnessAmp) + "%)";
return color;
}
lightnessAmp
рассчитывается из текущей даты и времени. Цвет меняется, если dtoDate
в течение последних 24 часов.
Точная ошибка заключается в следующем:
Выражение изменилось после того, как оно было проверено. Предыдущее значение: «hsl (123, 80%, 49%)». Текущее значение: «hsl (123, 80%, 48%)»
Я знаю, что исключение появляется в режиме разработки только в момент проверки значения. Если проверенное значение отличается от обновленного значения, генерируется исключение.
Поэтому я попытался обновить текущую дату и время на каждом жизненном цикле следующим методом ловушки, чтобы предотвратить исключение:
ngAfterViewChecked()
{
console.log( "! changement de la date du composant !" );
this.dateNow = new Date();
}
... но безуспешно.
angular
typescript
time
styles
components
Энтони Бренельер
источник
источник
Ответы:
Запустите обнаружение изменений явно после изменения:
источник
ngOnInit()
обычно это первое место. Если код зависит от визуализируемого DOMngAfterViewInit()
илиngAfterContentInit()
есть следующие варианты.ngOnChanges()
хорошо подходит, если код должен выполняться каждый раз, когда ввод был изменен.ngDoCheck()
для пользовательского обнаружения изменений. На самом деле я не знаю, для чегоngAfterViewChecked()
лучше всего использовать. Я думаю, что это называется до или послеngAfterViewInit()
.clientWidth
, и т. Д.TL; DR
Хотя это обходной путь, иногда действительно трудно решить эту проблему каким-либо более приятным способом, поэтому не вините себя, если вы используете этот подход. Это нормально.
Примеры : Первая проблема [ ссылка ], Решена с помощью
setTimeout()
[ ссылка ]Как избежать
Как правило, эта ошибка обычно происходит после добавления чего-либо (даже в родительских / дочерних компонентах)
ngAfterViewInit
. Итак, первый вопрос - спросите себя - могу ли я жить безngAfterViewInit
? Возможно, вы куда-то перемещаете код (ngAfterViewChecked
может быть альтернативой).Пример : [ ссылка ]
Также
Также
ngAfterViewInit
причиной этого могут быть асинхронные вещи , влияющие на DOM. Также можно решить с помощьюsetTimeout
или добавивdelay(0)
оператор в трубе:Пример : [ ссылка ]
Приятного чтения
Хорошая статья о том, как отладить это и почему это происходит: ссылка
источник
Как упомянуто @leocaseiro по вопросу о github .
источник
Ее вы идете два решения!
1. Измените ChangeDetectionStrategy на OnPush
Для этого решения вы в основном говорите:
Быстрое решение:
Измените ваш компонент так, чтобы он использовал
ChangeDetectionStrategy.OnPush
С этим вещи, кажется, больше не работают. Это потому, что теперь вам придется делать Angular вызов
detectChanges()
вручную.Вот ссылка, которая помогла мне понять ChangeDetectionStrategy правильно: https://alligator.io/angular/change-detection-strategy/
2. Понимание ExpressionChangedAfterItHasBeenCheckedError
Вот небольшой отрывок из ответа tomonari_t о причинах этой ошибки, я попытался включить только те части, которые помогли мне понять это.
Полная статья показывает реальные примеры кода для каждой точки, показанной здесь.
Основной причиной является угловой жизненный цикл:
Следующие операции проверяются в цикле дайджеста:
И так, ошибка выдается, когда сравниваемые значения различны. Блогер Макс Корецкий заявил:
И, наконец, вот некоторые примеры из реальной жизни, которые обычно вызывают эту ошибку:
Каждый образец можно найти здесь (plunkr), в моем случае проблема заключалась в создании динамического компонента.
Кроме того, по собственному опыту я настоятельно рекомендую всем избегать
setTimeout
решения, в моем случае это вызвало «почти» бесконечный цикл (21 вызов, который я не хочу показывать вам, как их спровоцировать),Я бы порекомендовал всегда иметь в виду жизненный цикл Angular, чтобы вы могли учитывать, как они будут влиять при каждом изменении значения другого компонента. С этой ошибкой Angular говорит вам:
В том же блоге также говорится:
Краткое руководство для меня заключается в рассмотрении по крайней мере следующих двух вещей при кодировании ( я постараюсь дополнить его с течением времени ):
@Input
и@Output
директивы пытаются избежать запуска изменений lyfecycle , если компонент не будет полностью инициализирован.this.cdr.detectChanges();
, поскольку они могут вызвать больше ошибок, особенно когда вы имеете дело с большим количеством динамических данныхthis.cdr.detectChanges();
является обязательным, убедитесь, что используемые переменные (@Input, @Output, etc
) заполнены / инициализированы в правой точке обнаружения (OnInit, OnChanges, AfterView, etc
)Также
Если вы хотите полностью понять Angular Life Hook, я рекомендую вам прочитать официальную документацию здесь:
источник
ChangeDetectionStrategy
чтобыOnPush
исправить это для меня. У меня есть простой компонент, который имеет[disabled]="isLastPage()"
. Этот метод читаетMatPaginator
-ViewChild и возвращаетthis.paginator !== undefined ? this.paginator.pageIndex === this.paginator.getNumberOfPages() - 1 : true;
. Пагинатор не доступен сразу, но после того, как он был связан с использованием@ViewChild
. ИзменениеChangeDetectionStrategy
убрано, ошибка - и функционал все еще существует, как и прежде. Не уверен, какие недостатки у меня сейчас есть, но спасибо!OnPush
- то, что вам придется использоватьthis.cdr.detectChanges()
каждый раз, когда вы хотите обновить компонент. Я думаю, вы уже использовали егоВ нашем случае мы ИСПРАВЛЕНЫ, добавив changeDetection в компонент и вызвав DeteChanges () в ngAfterContentChecked, код следующий:
источник
Я думаю, что лучшее и самое чистое решение, которое вы можете себе представить, это:
Протестировано с Angular 5.2.9
источник
Небольшую работу вокруг я использовал много раз
Я в основном заменяю «ноль» на переменную, которую я использую в контроллере.
источник
Хотя уже есть много ответов и ссылка на очень хорошую статью об обнаружении изменений, я хотел бы привести здесь свои два цента. Я думаю, что проверка есть по какой-то причине, поэтому я подумал об архитектуре моего приложения и понял, что изменения в представлении могут быть обработаны с помощью
BehaviourSubject
правильного хука жизненного цикла. Итак, вот что я сделал для решения.В итоге я получил базовый класс JavaScript, и мне нужно инициализировать свой собственный заголовок календаря для компонента. Это требует
ViewChild
отрисовки перед тем, как отчитывается мой родитель, а это не так, как работает Angular. Вот почему я обернул нужное значение для моего шаблона вBehaviourSubject<View>(null)
:Затем, когда я могу быть уверен, что представление проверено, я обновляю эту тему значением из
@ViewChild
:Затем в моем шаблоне я просто использую
async
трубу. Без взлома с обнаружением изменений, без ошибок, работает без сбоев.Пожалуйста, не стесняйтесь спрашивать, если вам нужно больше деталей.
источник
Используйте значение формы по умолчанию, чтобы избежать ошибки.
Вместо того, чтобы использовать принятый ответ о применении detectChanges () в ngAfterViewInit () (что также позволило устранить ошибку в моем случае), я решил вместо этого сохранить значение по умолчанию для динамически обязательного поля формы, чтобы при последующем обновлении формы его действительность не изменяется, если пользователь решает изменить параметр в форме, который вызовет новые обязательные поля (и приведет к отключению кнопки отправки).
Это позволило сохранить небольшой кусочек кода в моем компоненте, и в моем случае ошибки удалось избежать.
источник
this.cdr.detectChanges()
Я получил эту ошибку, потому что я объявил переменную и позже хотел
изменить ее значение, используя
ngAfterViewInit
чтобы исправить это я перешел с
в
источник