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.