2017-02-12 13 views
6

Mam element nadrzędny, który wyświetla listę błędów sprawdzania poprawności i wyświetla listę komponentów podrzędnych z ngFor. Każdy komponent podrzędny wykonuje sprawdzanie poprawności podczas ngOnInit i wysyła wynik do komponentu nadrzędnego. Komponent nadrzędny nasłuchuje tego wyjścia i aktualizuje listę błędów walidacji, w wyniku którego zgłasza błąd:"Wyrażenie zostało zmienione po sprawdzeniu", gdy komponent podrzędny emituje na ngOnInit

Expression has changed after it was checked

Teraz rozumiem, dlaczego ten błąd jest wyrzucane - Na początku wykrywania zmian cykl błędy sprawdzania poprawności były w jednym stanie, a na końcu był w innym stanie, a to nie jest dozwolone.

Nie rozumiem, jak obejść ten problem. Komponent macierzysty musi wyświetlić listę błędów u góry strony, a każdy komponent podrzędny doda wyniki sprawdzania poprawności do tej listy. Jeśli jest to naruszenie jednokierunkowego przepływu danych, proszę powiedz mi, jak obejść ten problem w czysty sposób (tj. Nie owijając sprawdzania poprawności w setTimeout, nie zmieniając z niezmiennej listy na zmienną i nie wywołując jawnie detektor zmian ponownie po sprawdzeniu poprawności).

Plunker odtwarzając problem: https://plnkr.co/edit/q52A1DraNOnxZa0qGFDo?p=preview


EDIT

ja "rozwiązać" ten problem konstruując EventEmitter z isAsync flag

new EventEmitter(true)

Oznacza to, że wartości będą emitowane asynchronicznie, więc emitowane wartości będą wykrywane w kolejnym etapie wykrywania zmian. Myślę, że wynik jest taki sam jak zawijanie logiki w setTimeout, ale w ten sposób przynajmniej nie musimy zawijać naszego kodu w timeout wszędzie, gdzie możemy emitować wartość.

+0

dziękuję za twoją duszę. –

+0

Dzięki za asynchroniczne rozwiązanie! – Sal

Odpowiedz

3

Kątowy nie podoba się, gdy samo wykrywanie zmian powoduje zmiany i ngOnInit jest wywoływane przez wykrywanie zmian.

Wykrywanie zmian w trybie devMode uruchamia dodatkowe wykrywanie zmian po każdym uruchomieniu regularnego wykrywania zmian, aby sprawdzić, czy model jest stabilny. Jeśli model zmienił się podczas wykrywania zmian, zgłasza ten błąd.

Można opóźnić zmiany aż po wykryciu zmiany zakończeniu korzystania

ngOnInit() { 
    setTimeout(() => { 
     this.output.emit({value: true}); 
    } 
    } 

Plunker example

Update (patrz komentarz Ghetolay za poniżej)

ngOnInit is not called by change detection and you can do bind changes inside it. What you cannot do is making change on a parent from a child's ngOnInit cause this breaks unidirectional data flow.

Patrz także https://github.com/angular/angular/issues/10131#issuecomment-233369491

+0

Wyobraź sobie, że piszę komponent dla trzeciej strony, która podczas inicjalizacji musi wyprowadzić pewne dane, i nie wiem, jak ten komponent zostanie zintegrowany. Chyba że ja, bez żadnego intuicyjnego powodu, zawijam tę logikę inicjalizacyjną w 'setTimeout', aplikacja integrująca mój komponent wyrzuci ten błąd i naprawi go poza ich kontrolą. Jestem albo A) brakuje mi tego, jak powinienem poprawnie wyprowadzać wartości z komponentów potomnych, albo B) z powodu ograniczenia detektora zmian trzeba dodać wszędzie "setTimeouts", aby zatrzymać wykrywanie błędu przez detektor zmian. – Cristian

+0

Myślę, że dodatkowy cykl wykrywania zmian jest nieunikniony. Angular znajduje się pośrodku detekcji zmian, gdy nastąpi ta zmiana. Dlatego potrzebny jest kolejny cykl wykrywania zmian, aby ujednolicony przepływ danych działał. –

+0

Moim głównym zmartwieniem jest integracja, a nie dodatkowy cykl CD, o którym mój komentarz nie wspomniał. Skąd mam wiedzieć, kiedy muszę opakować logikę w 'setTimeout'? Jak wytłumaczyć moim kolegom, że aby zapobiec problemom z wykrywaniem zmian, powinni zawinąć całą logikę inicjalizacji w 'setTimeout', * na wszelki wypadek *? – Cristian

0

Nie możesz nic zmienić w ngOnInit. Zespół Angular 2 odmówił uznania tego za błąd (#10131), więc tak, musisz zrobić to w nieczysty sposób: setTimeout(..., 0) lub Promise.resolve().then(...).

+0

Nie jestem pewien, czy podążam za "nie mogę zmienić niczego w' ngOnInit' ".. jaki jest więc jego cel? Rozumiem, że 'ngOnInit' jest zasadniczo używany do konfigurowania danych/subskrypcji zamiast konstruktora w celach testowych. – Cristian

+0

Tak, chodzi o to, aby rozpocząć pobieranie danych w 'ngOnInit', ale robienie tego w konstruktorze jest złe dla testowania, jednak w rzeczywistości będziesz musiał ustawić pola komponentów w odpowiedzi na wartości właściwości wejściowych i nie ma właściwego miejsca na to działania, jedynym sposobem jest wykorzystanie opóźnień. – kemsky

+0

Taki sam jak odpowiedź gunter o 'ngOnInit' zobacz mój komentarz. – Ghetolay

Powiązane problemy