Wyzwalanie detekcji zmian ręcznie w Angular


387

Piszę komponent Angular, który ma właściwość Mode(): string.

Chciałbym móc ustawić tę właściwość programowo nie w odpowiedzi na żadne zdarzenie.

Problem polega na tym, że w przypadku braku zdarzenia przeglądarki powiązanie szablonu {{Mode}}nie jest aktualizowane.

Czy istnieje sposób, aby ręcznie uruchomić to wykrywanie zmian?

Odpowiedzi:


640

Spróbuj jednego z tych:

  • ApplicationRef.tick()- podobne do AngularJS $rootScope.$digest()- tzn. sprawdź pełne drzewo komponentów
  • NgZone.run(callback)- podobny do $rootScope.$apply(callback)- tj. oceny funkcji oddzwaniania w strefie kątowej. Myślę, ale nie jestem pewien, czy to kończy sprawdzanie pełnego drzewa komponentów po wykonaniu funkcji wywołania zwrotnego.
  • ChangeDetectorRef.detectChanges()- podobny do $scope.$digest()- tzn. sprawdź tylko ten komponent i jego elementy potomne

Można wstrzyknąć ApplicationRef, NgZonealbo ChangeDetectorRefdo swojego urządzenia.


1
Dzięki, zdecydowałem się na trzecie rozwiązanie, aby nie sprawdzać wszystkiego, ponieważ zmiany są dość zlokalizowane. Powinienem sprawdzić inne opcje, kiedy będę miał więcej czasu. Czy każdy wybór ma wpływ na wydajność?
jz87

36
+1 dla ChangeDetectorRef.detectChanges(). walidatory odpalały, zanim moja dyrektywa mogła zaktualizować wartość wejściową.
ps2goat

7
ApplicationRef.tick () i ChangeDetectorRef.detectChanges () są nadal obecne w wersji 2.0.0 final.
Max Mumford

51
Pomyślałem, że o tym wspomnę. To nie są metody statyczne, to metody instancji. Będziesz musiał wstrzyknąć te klasy jako usługi.
Stephen Paul,

1
ApplicationRef.tick () pomógł rozwiązać problem z FireFox v17 (<20)
Dan J

123

Użyłem akceptowanego źródła odpowiedzi i chciałbym podać przykład, ponieważ dokumentacja Angular 2 jest bardzo trudna do odczytania, mam nadzieję, że jest to łatwiejsze:

  1. Importuj NgZone:

    import { Component, NgZone } from '@angular/core';
    
  2. Dodaj go do konstruktora klasy

    constructor(public zone: NgZone, ...args){}
    
  3. Uruchom kod za pomocą zone.run:

    this.zone.run(() => this.donations = donations)
    

6
gdzie należy umieścić zone.runkod i czym dokładnie jest donations?
suku

Darowizny @suku to dowolna właściwość, którą chcesz zaktualizować, więc może to być this.foo = bar. zone.run idzie tam, gdzie chcesz aktualizować.
Matthew Opcjonalnie Meehan

4
Użyłem tego rozwiązania, aby wymusić aktualizację widoku podczas korzystania z document.addEventListener („resume”, callback)
marcovtwout

71

Byłem w stanie zaktualizować go za pomocą markForCheck ()

Importuj ChangeDetectorRef

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

Wstrzyknąć i utworzyć go

constructor(private ref: ChangeDetectorRef) { 
}

Na koniec nastąpi wykrycie zmiany znaku

this.ref.markForCheck();

Oto przykład, w którym działa markForCheck (), a wykrywanieChanges () nie.

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

EDYCJA: Ten przykład nie przedstawia już problemu :( Wydaje mi się, że może działać na nowszej wersji Angular, gdzie został naprawiony.

(Naciśnij STOP / RUN, aby uruchomić ponownie)


Punkt Goo dla funkcji DetChanges () nie działa. Zauważyłem ten sam problem i stwierdziłem, że działa, jeśli wykrywanie zmiany nie jest OnPush. Dobrze byłoby uzyskać wyjaśnienie tego ...
Christian

2
Wygląda na to, że detekcja zmian faktycznie działa w tym plunkerze? Czy coś brakuje?
Jared_C,

1
Należy zauważyć, że ChangeDetectorRef działa tylko w komponentach
kevinius

(!) To zły przykład, przepraszam. Przykład niczego nie pokazuje. Pierwszy element zostanie po prostu nadpisany. Po prostu trochę wyreguluj timery ...
Peter Stegnar,

Ten przykład nie przedstawia już problemu :( Wydaje mi się, że może działać na nowszej wersji Angular, gdzie został naprawiony.
Nuno Tomas

7

W Angular 2+ wypróbuj dekorator @Input

Pozwala na pewne ładne powiązanie właściwości między komponentami nadrzędnymi i podrzędnymi.

Najpierw utwórz zmienną globalną w obiekcie nadrzędnym, aby przechowywać obiekt / właściwość, która zostanie przekazana do dziecka.

Następnie utwórz zmienną globalną w obiekcie potomnym, aby przechowywać obiekt / właściwość przekazaną od rodzica.

Następnie w nadrzędnym pliku HTML, w którym używany jest szablon podrzędny, dodaj notację w nawiasach kwadratowych z nazwą zmiennej podrzędnej, a następnie ustaw ją na wartość równą nazwie zmiennej nadrzędnej. Przykład:

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

Na koniec, jeśli właściwość potomna jest zdefiniowana w komponencie potomnym, dodaj dekorator wejściowy:

@Input()
public childVariable: any

Gdy zmienna nadrzędna zostanie zaktualizowana, powinna przekazać aktualizacje do komponentu potomnego, który zaktualizuje jego HTML.

Ponadto, aby uruchomić funkcję w komponencie potomnym, spójrz na ngOnChanges.


2
NIE ... to jest problem ... jeśli aktualizujesz w rodzicu ... powiedz, że exmaple jest aktualizowany "przez referencję" w metodzie statycznej dziecko nie odbierze go, ponieważ nie nastąpiło wykrycie zmiany
Bhail

Od kilku dni mam ten sam problem. Próbuję pobrać dane z zaplecza PHP i dane w ogóle się nie aktualizują. Na Microsoft Edge działa dobrze, ale w innej przeglądarce nie działa.
Wciąż

1

ChangeDetectorRef.detectChanges () - podobnie jak $ scope. $ Digest () - tzn. Sprawdź tylko ten komponent i jego dzieci

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.