Wiem, że nie jestem pierwszą, która o to pyta, ale nie mogę znaleźć odpowiedzi w poprzednich pytaniach. Mam to w jednym komponencie
<div class="col-sm-5">
<laps
[lapsData]="rawLapsData"
[selectedTps]="selectedTps"
(lapsHandler)="lapsHandler($event)">
</laps>
</div>
<map
[lapsData]="rawLapsData"
class="col-sm-7">
</map>
W kontrolerze rawLapsdata
ulega od czasu do czasu mutacjom.
W laps
programie dane są wyprowadzane jako HTML w formacie tabelarycznym. To zmienia się za każdym razem rawLapsdata
.
Mój map
komponent musi być użyty ngOnChanges
jako wyzwalacz do przerysowywania znaczników na Mapie Google. Problem polega na tym, że ngOnChanges nie odpala przy rawLapsData
zmianach w rodzicu. Co mogę zrobić?
import {Component, Input, OnInit, OnChanges, SimpleChange} from 'angular2/core';
@Component({
selector: 'map',
templateUrl: './components/edMap/edMap.html',
styleUrls: ['./components/edMap/edMap.css']
})
export class MapCmp implements OnInit, OnChanges {
@Input() lapsData: any;
map: google.maps.Map;
ngOnInit() {
...
}
ngOnChanges(changes: { [propName: string]: SimpleChange }) {
console.log('ngOnChanges = ', changes['lapsData']);
if (this.map) this.drawMarkers();
}
Aktualizacja: ngOnChanges nie działa, ale wygląda na to, że lapsData jest aktualizowany. W ngInit jest odbiornikiem zdarzeń dla zmian zoomu, który również wywołuje this.drawmarkers
. Kiedy zmieniam zoom, rzeczywiście widzę zmianę w znacznikach. Jedynym problemem jest to, że nie otrzymuję powiadomienia w momencie zmiany danych wejściowych.
W rodzicu mam tę linię. (Przypomnij sobie, że zmiana jest odzwierciedlona w okrążeniach, ale nie na mapie).
this.rawLapsData = deletePoints(this.rawLapsData, this.selectedTps);
Zauważ, że this.rawLapsData
sam jest wskaźnikiem do środka dużego obiektu json
this.rawLapsData = this.main.data.TrainingCenterDatabase.Activities[0].Activity[0].Lap;
zone.run(...)
powinno to zrobić.ngOnChanges()
nie zostanie wywołana. Możesz użyćngDoCheck()
i zaimplementować własną logikę, aby określić, czy zawartość tablicy uległa zmianie.lapsData
jest aktualizowany, ponieważ ma / jest odniesieniem do tej samej tablicy corawLapsData
.Odpowiedzi:
rawLapsData
nadal wskazuje tę samą tablicę, nawet jeśli zmodyfikujesz zawartość tablicy (np. dodasz elementy, usuniesz elementy, zmienisz pozycję).Podczas wykrywania zmian, gdy Angular sprawdza właściwości wejściowe komponentów pod kątem zmiany, używa (zasadniczo)
===
do sprawdzania brudnego. W przypadku tablic oznacza to, że odwołania do tablic (tylko) są sprawdzane na brudno. PonieważrawLapsData
odwołanie do tablicy się nie zmienia,ngOnChanges()
nie zostanie wywołane.Przychodzą mi do głowy dwa możliwe rozwiązania:
Zaimplementuj
ngDoCheck()
i przeprowadź własną logikę wykrywania zmian, aby określić, czy zawartość tablicy uległa zmianie. (Dokument Lifecycle Hooks zawiera przykład ).Przypisz nową tablicę do
rawLapsData
każdej zmiany zawartości tablicy. NastępniengOnChanges()
zostanie wywołana, ponieważ tablica (odniesienie) pojawi się jako zmiana.W swojej odpowiedzi podałeś inne rozwiązanie.
Powtarzam tutaj kilka komentarzy na temat PO:
laps
komponencie twój kod / szablon zapętla każdy wpis wlapsData
tablicy i wyświetla zawartość, więc na każdym wyświetlanym fragmencie danych istnieją powiązania kątowe.===
sprawdzania), nadal (domyślnie) po brudnym sprawdzaniu wszystkich powiązań szablonu. Kiedy któraś z tych zmian się zmieni, Angular zaktualizuje DOM. To właśnie widzisz.maps
Komponent prawdopodobnie nie ma żadnych powiązań w swoim szablonie do jegolapsData
własności wejściowego, prawda? To wyjaśniałoby różnicę.Zauważ, że
lapsData
w obu komponentach iw komponencierawLapsData
macierzystym wszystkie wskazują na tę samą / jedną tablicę. Więc nawet jeśli Angular nie zauważa żadnych (referencyjnych) zmian welapsData
właściwościach wejściowych, komponenty „pobierają” / widzą zmiany zawartości tablicy, ponieważ wszystkie współużytkują / odwołują się do tej jednej tablicy. Nie potrzebujemy Angulara do propagowania tych zmian, tak jak w przypadku typu pierwotnego (string, number, boolean). Ale w przypadku typu prymitywnego każda zmiana wartości zawsze by się uruchomiłangOnChanges()
- co jest czymś, co wykorzystujesz w swojej odpowiedzi / rozwiązaniu.Jak już zapewne wiesz, właściwości wejściowe obiektu zachowują się tak samo, jak właściwości wejściowe tablicy.
źródło
Nie jest to najczystsze podejście, ale możesz po prostu sklonować obiekt za każdym razem, gdy zmieniasz wartość?
Myślę, że wolałbym to podejście niż wdrażanie własnego,
ngDoCheck()
ale może ktoś taki jak @ GünterZöchbauer mógłby się wtrącić.źródło
W przypadku tablic można to zrobić w następujący sposób:
W
.ts
pliku (komponent nadrzędny), w którym aktualizujesz,rawLapsData
zrób to w ten sposób:Rozwiązanie:
i
ngOnChanges
wywoła komponent potomnyźródło
Jako rozszerzenie drugiego rozwiązania Marka Rajcoka
możesz sklonować zawartość tablicy w następujący sposób:
Wspominam o tym, ponieważ
nie działa dla mnie. Mam nadzieję, że to pomoże.
źródło
Jeśli dane pochodzą z biblioteki zewnętrznej, może być konieczne uruchomienie w niej instrukcji aktualizacji danych
zone.run(...)
. Wstrzyknijzone: NgZone
za to. Jeśli możesz już uruchomić instancję biblioteki zewnętrznejzone.run()
, możeszzone.run()
później nie potrzebować .źródło
$scope.$apply
?zone.run
jest podobny do$scope.apply
.Służy
ChangeDetectorRef.detectChanges()
do mówienia Angularowi, aby uruchomił wykrywanie zmian podczas edycji zagnieżdżonego obiektu (którego pomija z brudnym sprawdzaniem).źródło
Mam 2 rozwiązania, aby rozwiązać twój problem
ngDoCheck
do wykrywaniaobject
zmian lub niezmienionych danychobject
do nowego adresu pamięciobject = Object.create(object)
z komponentu nadrzędnego.źródło
Wykrywanie zmian nie jest wyzwalane po zmianie właściwości obiektu (w tym obiektu zagnieżdżonego). Jednym z rozwiązań byłoby ponowne przypisanie nowego odniesienia do obiektu za pomocą funkcji clone () „lodash”.
źródło
Moje rozwiązanie „hack” to
selectedTps zmienia się w tym samym czasie co rawLapsData, co daje mapie kolejną szansę na wykrycie zmiany za pomocą prostszego typu
obiektupierwotnego. NIE jest elegancki, ale działa.źródło
Oto hack, który właśnie wyciągnął mnie z kłopotów z tym.
A więc podobny scenariusz do OP - mam zagnieżdżony komponent Angular, który wymaga przesłania danych, ale dane wejściowe wskazują na tablicę i jak wspomniano powyżej, Angular nie widzi zmiany, ponieważ nie bada zawartość tablicy.
Aby to naprawić, konwertuję tablicę na ciąg znaków, aby Angular wykrył zmianę, a następnie w zagnieżdżonym komponencie dzielę (',') ciąg z powrotem na tablicę i znowu szczęśliwe dni.
źródło
Natknąłem się na tę samą potrzebę. Dużo czytam na ten temat, więc oto moja miedź na ten temat.
Jeśli chcesz, aby wykrywanie zmian było wykonywane przy wypychaniu, to miałbyś je mieć, gdy zmieniasz wartość obiektu w środku, prawda? I miałbyś to również, gdybyś w jakiś sposób usuwał przedmioty.
Jak już wspomniano, użycie changeDetectionStrategy.onPush
Powiedzmy, że masz ten komponent, który utworzyłeś za pomocą changeDetectionStrategy.onPush:
Następnie popchnąłbyś element i wywołał wykrywanie zmiany:
lub możesz usunąć element i wywołać wykrywanie zmian:
albo zmienisz wartość atrybutu elementu i uruchomisz wykrywanie zmiany:
Treść odświeżenia:
Metoda slice zwraca dokładnie to samo Array, a znak [=] tworzy do niej nowe odniesienie, wyzwalając wykrywanie zmiany za każdym razem, gdy jest to potrzebne. Łatwe i czytelne :)
Pozdrowienia,
źródło
Wypróbowałem wszystkie wymienione tutaj rozwiązania, ale z jakiegoś powodu
ngOnChanges()
nadal nie odpaliłem. Więc zadzwoniłem zthis.ngOnChanges()
po wywołaniu usługi, która ponownie zapełnia moje tablice i zadziałało ... prawda? prawdopodobnie nie. Schludny? cholera nie. Pracuje? tak!źródło
ok, więc moim rozwiązaniem było:
I to wyzwala mnie ngOnChanges
źródło
Musiałem stworzyć do tego hack -
źródło
W moim przypadku były to zmiany wartości obiektu, których
ngOnChange
nie przechwytywano. Kilka wartości obiektów jest modyfikowanych w odpowiedzi na wywołanie interfejsu API. PonownengOnChange
zainicjowanie obiektu rozwiązało problem i spowodowało wyzwolenie elementu podrzędnego.Coś jak
źródło
Kiedy manipulujesz danymi, takimi jak:
Następnie powinieneś użyć, aby wykryć zmiany:
Ponieważ kątowe ngOnchanges nie są w stanie wykryć zmian w szyku, obiektach, musimy przypisać nowe odniesienie. Działa za każdym razem!
źródło