Запуск обнаружения изменений вручную в Angular

387

Я пишу угловой компонент, который имеет свойство Mode(): string.

Я хотел бы иметь возможность установить это свойство программно, а не в ответ на любое событие.

Проблема в том, что при отсутствии события браузера привязка шаблона {{Mode}}не обновляется.

Есть ли способ вызвать это обнаружение изменений вручную?

jz87
источник

Ответы:

640

Попробуйте один из них:

  • ApplicationRef.tick()- аналогичен AngularJS $rootScope.$digest()- то есть проверьте полное дерево компонентов
  • NgZone.run(callback)- аналогично $rootScope.$apply(callback)- т.е. оценивать функцию обратного вызова внутри угловой зоны. Я думаю, но я не уверен, что это заканчивается проверкой полного дерева компонентов после выполнения функции обратного вызова.
  • ChangeDetectorRef.detectChanges()- аналогично $scope.$digest()- т.е. проверять только этот компонент и его дочерние элементы

Вы можете вводить ApplicationRef, NgZoneили ChangeDetectorRefв компонент.

Марк Райкок
источник
1
Спасибо, я выбрал 3-е решение, чтобы не проверять все, так как изменения довольно локализованы. Я должен изучить другие варианты, когда у меня будет больше времени. Есть ли какие-либо последствия для производительности с каждым выбором?
jz87
36
+1 за ChangeDetectorRef.detectChanges(). валидаторы стреляли до того, как моя директива смогла обновить значение ввода.
ps2goat
7
ApplicationRef.tick () и ChangeDetectorRef.detectChanges () по-прежнему присутствуют в финальной версии 2.0.0.
Макс Мамфорд
51
Просто подумал, что упомяну это. Это не статические методы, это методы экземпляра. Вам нужно будет внедрить эти классы в качестве услуг.
Стивен Пол
1
ApplicationRef.tick () помог решить проблему с FireFox v17 (<20)
Дан, J
124

Я использовал принятую ссылку на ответ и хотел бы привести пример, поскольку документацию по Angular 2 очень очень трудно читать, я надеюсь, что это проще:

  1. Импорт NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Добавьте его в свой конструктор класса

    constructor(public zone: NgZone, ...args){}
    
  3. Запустите код с zone.run:

    this.zone.run(() => this.donations = donations)
    
места
источник
6
где вы должны поместить zone.runкод и что именно donations?
suku
1
@suku donations - это любое свойство, которое вы хотите обновить, поэтому это может быть this.foo = bar. zone.run идет туда, где вы хотите что-то обновить.
Мэтью Факультативно Михан
4
Я использовал это решение для принудительного обновления представления при использовании document.addEventListener ("resume", callback)
marcovtwout
71

Я смог обновить его с помощью markForCheck ()

Импортировать ChangeDetectorRef

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

Внедрить и создать его

constructor(private ref: ChangeDetectorRef) { 
}

Наконец отметьте обнаружение изменения, чтобы иметь место

this.ref.markForCheck();

Вот пример, где markForCheck () работает, а deteChanges () - нет.

https://plnkr.co/edit/RfJwHqEVJcMU9ku9XNE7?p=preview

РЕДАКТИРОВАТЬ: Этот пример больше не отображает проблему :( Я думаю, что это может быть запущена более новая версия Angular, где она исправлена.

(Нажмите STOP / RUN, чтобы запустить его снова)

Нуно томас
источник
Goo point для DetectChanges () не работает. Я заметил ту же проблему и обнаружил, что она работает, если обнаружение изменений не OnPush. Было бы хорошо получить объяснение этому ...
Кристиан
2
Похоже, что на этом плункере действительно работает DeteChanges? Я что-то пропустил?
Jared_C
1
Следует
помнить,
(!) Это плохой пример, извините. Пример не показывает ничего. Первый пункт просто перезаписывается. Просто немного отрегулируйте таймеры ...
Питер Стегнар
Этот пример больше не отображает проблему :( Я полагаю, что она может работать на более новой версии Angular, где она исправлена.
Nuno Tomas
7

В Angular 2+ попробуйте декоратор @Input

Это допускает некоторое хорошее связывание свойств между родительскими и дочерними компонентами.

Сначала создайте глобальную переменную в родительском объекте для хранения объекта / свойства, которые будут переданы дочернему элементу.

Затем создайте глобальную переменную в дочернем объекте для хранения объекта / свойства, переданного от родительского объекта.

Затем в родительском html, где используется дочерний шаблон, добавьте нотацию в квадратных скобках с именем дочерней переменной, а затем установите ее равной имени родительской переменной. Пример:

<child-component-template [childVariable] = parentVariable>
</child-component-template>

Наконец, если дочернее свойство определено в дочернем компоненте, добавьте декоратор ввода:

@Input()
public childVariable: any

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

Кроме того, чтобы вызвать функцию в дочернем компоненте, взгляните на ngOnChanges.

Джереми Сваггер
источник
2
НЕТ ... вот в чем проблема ... если вы обновляете в родителе ... скажем, для exmaple обновляется "по ссылке" в статическом методе, ребенок не поднимет его, так как обнаружение изменений не
произошло
У меня такая же проблема уже несколько дней. Я пытаюсь получить данные из бэкэнда PHP, и данные вообще не обновляются. В Microsoft Edge работает нормально, а в других браузерах - нет. Я продолжаю получать данные, которые я впервые получил при запуске, но если данные изменяются, они не обновляются при просмотре
el6976
1

ChangeDetectorRef.detectChanges () - аналогично $ scope. $ Digest () - т.е. проверять только этот компонент и его дочерние элементы

Chetann
источник