Mam element nadrzędny ( CategoryComponent ), element podrzędny ( videoListComponent ) i ApiService.
Mam większość z tego działa dobrze, tj. Każdy komponent może uzyskać dostęp do Json API i uzyskać odpowiednie dane za pomocą obserwowalnych.
Obecnie komponent listy wideo po prostu pobiera wszystkie filmy, chciałbym to przefiltrować tylko do filmów w określonej kategorii. Osiągnąłem to, przekazując kategorię ID do dziecka @Input()
.
CategoryComponent.html
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
Działa to i gdy zmienia się nadrzędna kategoria CategoryComponent, wówczas wartość przechodzi przez kategorię @Input()
id, ale muszę to wykryć w VideoListComponent i ponownie zażądać tablicy wideo za pośrednictwem APIService (z nowym categoryId).
W AngularJS zrobiłbym a $watch
na zmiennej. Jaki jest najlepszy sposób, aby sobie z tym poradzić?
źródło
Odpowiedzi:
W rzeczywistości istnieją dwa sposoby wykrywania i reagowania, gdy dane wejściowe zmieniają się w elemencie potomnym w angular2 +:
Łącza do dokumentacji: ngOnChanges, SimpleChanges, SimpleChange
Demo Przykład: Spójrz na tego plunkera
Link do dokumentacji: Look tutaj .
Przykład demonstracyjny: spójrz na tego plunkera .
JAKIEGO PODEJŚCIA POWINIENEŚ WYKORZYSTAĆ?
Jeśli twój komponent ma kilka danych wejściowych, to jeśli użyjesz ngOnChanges (), otrzymasz wszystkie zmiany dla wszystkich danych naraz w ngOnChanges (). Korzystając z tego podejścia, możesz także porównać bieżące i poprzednie wartości zmienionego wejścia i odpowiednio podjąć działania.
Jeśli jednak chcesz coś zrobić, gdy zmienia się tylko jedno pojedyncze wejście (i nie przejmujesz się pozostałymi danymi wejściowymi), łatwiejsze może być ustawienie właściwości wprowadzania. Jednak to podejście nie zapewnia wbudowanego sposobu porównywania poprzednich i bieżących wartości zmienionych danych wejściowych (co można łatwo zrobić za pomocą metody cyklu życia ngOnChanges).
EDYCJA 2017-07-25: WYKRYWANIE ZMIAN KĄTOWYCH MOŻE NIE POŻAROWAĆ W NIEKTÓRYCH OKOLICZNOŚCIACH
Zwykle wykrywanie zmian zarówno dla metody ustawiającej, jak i ngOnChanges będzie uruchamiane za każdym razem, gdy składnik nadrzędny zmienia dane, które przekazuje do dziecka, pod warunkiem, że dane są pierwotnym typem danych JS (ciąg, liczba, wartość logiczna) . Jednak w poniższych scenariuszach nie będzie działać i musisz podjąć dodatkowe działania, aby działało.
Jeśli używasz zagnieżdżonego obiektu lub tablicy (zamiast pierwotnego typu danych JS) do przekazywania danych z rodzica na dziecko, wykrywanie zmian (przy użyciu settera lub ngchanges) może się nie uruchomić, jak wspomniano również w odpowiedzi użytkownika: muetzerich. Rozwiązania znajdziesz tutaj .
Jeśli mutujesz dane poza kontekstem kątowym (tj. Zewnętrznie), wówczas kątowy nie będzie wiedział o zmianach. Być może będziesz musiał użyć ChangeDetectorRef lub NgZone w swoim komponencie, aby uświadomić kątowe zmiany zewnętrzne i tym samym uruchomić wykrywanie zmian. Zobacz to .
źródło
doSomething
metodę i wziąć 2 argumenty nowe i stare wartości przed ustawieniem nowej wartości, w inny sposób zapisuje starą wartość przed ustawieniem i wywołaniem metody po tym.Użyj
ngOnChanges()
metody cyklu życia w swoim komponencie.Oto Dokumenty .
źródło
MyComponent.myArray = []
, ale jeśli wartość wejściowa jest zmieniony przykładMyComponent.myArray.push(newValue)
,ngOnChanges()
nie jest wyzwalany. Wszelkie pomysły na temat uchwycenia tej zmiany?ngOnChanges()
nie jest wywoływany, gdy zmieni się zagnieżdżony obiekt. Może znajdziesz rozwiązanie tutajOtrzymywałem błędy w konsoli, a także w kompilatorze i IDE, gdy użyłem tego
SimpleChanges
typu w sygnaturze funkcji. Aby uniknąć błędów,any
zamiast tego użyj słowa kluczowego w podpisie.EDYTOWAĆ:
Jak wskazał Jon poniżej, możesz używać
SimpleChanges
podpisu, używając notacji nawiasowej zamiast notacji kropkowej.źródło
SimpleChanges
interfejs u góry pliku?<my-user-details [user]="selectedUser"></my-user-details>
.). Do tej właściwości można uzyskać dostęp z klasy SimpleChanges poprzez wywołaniechanges.user.currentValue
. Powiadomienieuser
jest powiązane w czasie wykonywania i nie jest częścią obiektu SimpleChangesngOnChanges(changes: {[propName: string]: SimpleChange}) { console.log('onChanges - myProp = ' + changes['myProp'].currentValue); }
Najbezpieczniejszym zakład jest pójść z udostępnionego serwisu zamiast z
@Input
parametru. Ponadto@Input
parametr nie wykrywa zmian w złożonym typie zagnieżdżonego obiektu.Prosta przykładowa usługa jest następująca:
Możesz użyć podobnej implementacji w innych komponentach, a wszystkie twoje komponenty będą miały takie same wspólne wartości.
źródło
@Input
Parametr @JoshuaKemmerer nie wykrywa zmian w złożonym typie zagnieżdżonego obiektu, ale robi to w prostych obiektach natywnych.Chcę tylko dodać, że istnieje inny hak cyklu życia,
DoCheck
który jest przydatny, jeśli@Input
wartość nie jest wartością pierwotną.Mam tablicę jako taką,
Input
więc nie wywołuje toOnChanges
zdarzenia, gdy zawartość się zmienia (ponieważ sprawdzanie, czy robi to Angular, jest „proste” i nie głębokie, więc tablica nadal jest tablicą, mimo że zawartość tablicy się zmieniła).Następnie wdrażam niestandardowy kod sprawdzający, aby zdecydować, czy chcę zaktualizować mój widok za pomocą zmienionej macierzy.
źródło
spróbuj użyć tej metody. Mam nadzieję że to pomoże
źródło
Możesz także mieć obserwowalny, który uruchamia zmiany w komponencie nadrzędnym (CategoryComponent) i robić to, co chcesz zrobić w subskrypcji w komponencie podrzędnym. (videoListComponent)
źródło
Tutaj ngOnChanges uruchamia się zawsze, gdy zmienia się twoja właściwość wejściowa:
źródło
To rozwiązanie wykorzystuje klasę proxy i oferuje następujące zalety:
ngOnChanges()
Przykładowe użycie:
Funkcja użyteczności:
źródło
Jeśli nie chcesz używać metody ngOnChange implement og onChange (), możesz również subskrybować zmiany określonego elementu według zdarzenia valueChanges , ETC.
});
napisał markForCheck () z powodu użycia w tym oświadczeniu:
źródło
Możesz także przekazać EventEmitter jako dane wejściowe. Nie jestem pewien, czy jest to najlepsza praktyka ...
CategoryComponent.ts:
CategoryComponent.html:
I w VideoListComponent.ts:
źródło