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


387

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

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

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

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

Ответы:


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 () - т.е. проверять только этот компонент и его дочерние элементы

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.