Jak korzystać z nowej opcji statycznej dla @ViewChild w Angular 8?

204

Jak skonfigurować nowe dziecko potomne widoku Angular 8?

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

vs

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

Który jest lepszy? Kiedy powinienem używać static:truevs static:false?

Patrik Laszlo
źródło

Odpowiedzi:

237

W większości przypadków będziesz chciał użyć {static: false}. Ustawienie tego w ten sposób zapewni dopasowanie do zapytań, które zależą od rozdzielczości wiązania (jak dyrektywy strukturalne *ngIf, etc...).

Przykład zastosowania static: false:

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

static: falseBędzie domyślne zachowanie awaryjna w Kątowymi 9. Czytaj więcej tutaj i tutaj

{ static: true }Opcja została wprowadzona w celu wspierania tworzenia osadzonych poglądy na bieżąco. Gdy tworzysz widok dynamicznie i chcesz uzyskać do niego dostęp TemplateRef, nie będziesz w stanie tego zrobić, ngAfterViewInitponieważ spowoduje to ExpressionHasChangedAfterCheckedbłąd. Ustawienie flagi statycznej na true spowoduje utworzenie widoku w ngOnInit.

Niemniej jednak:

W większości innych przypadków najlepszą praktyką jest użycie {static: false}.

Pamiętaj jednak, że { static: false }opcja zostanie ustawiona jako domyślna w Angular 9. Co oznacza, że ​​ustawienie flagi statycznej nie jest już konieczne, chyba że chcesz użyć tej static: trueopcji.

Możesz użyć polecenia kątowego cli, ng updateaby automatycznie zaktualizować bieżącą bazę kodu.

Aby uzyskać przewodnik migracji i dodatkowe informacje na ten temat, możesz sprawdzić tutaj i tutaj

Jaka jest różnica między zapytaniami statycznymi a dynamicznymi?

Opcja statyczna dla zapytań @ViewChild () i @ContentChild () określa, kiedy wyniki zapytania będą dostępne.

W przypadku zapytań statycznych (static: true) zapytanie jest rozwiązywane po utworzeniu widoku, ale przed uruchomieniem wykrywania zmian. Jednak wynik nigdy nie będzie aktualizowany, aby odzwierciedlić zmiany w twoim widoku, takie jak zmiany bloków ngIf i ngFor.

W przypadku zapytań dynamicznych (static: false) zapytanie jest rozwiązywane po ngAfterViewInit () lub ngAfterContentInit () odpowiednio dla @ViewChild () i @ContentChild (). Wynik zostanie zaktualizowany o zmiany w twoim widoku, takie jak zmiany bloków ngIf i ngFor.

Poul Kruijt
źródło
Zaktualizuj link do dokumentów kątowych (zmienionych po wydaniu) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Nie mogę uzyskać dostępu do wystąpienia childView. Cały czas mówi niezdefiniowane.
Nesan Mano
Czy możesz podać link do informacji o usunięciu opcji statycznej w Angular 9?
Alex Marinov,
@AlexMarinov Zaktualizowałem moją odpowiedź, aby wyjaśnić, co się wydarzy w Angular 9. Link do tego jest w przewodniku migracji
Poul Kruijt
1
@ MinhNghĩa, jeśli zagnieżdżasz cały komponent poza szablonem komponentu, możesz go użyć { static: true }, ale jeśli nie ma bezpośredniej potrzeby dostępu do ViewChild wewnątrz ngOnInit, powinieneś po prostu użyć { static: false }.
Poul Kruijt
87

Zasadniczo możesz wybrać następujące opcje:

  • { static: true }musi być ustawiony, gdy chcesz uzyskać dostęp do ViewChildin ngOnInit.

  • { static: false }można uzyskać dostęp tylko w ngAfterViewInit. To jest również to, do czego chcesz się zastosować, gdy masz dyrektywę strukturalną (tj. *ngIf) Dotyczącą swojego elementu w szablonie.

dave0688
źródło
2
Uwaga: W Angular 9 flaga statyczna ma domyślną wartość false, więc „wszelkie flagi {static: false} można bezpiecznie usunąć”. Dokumentacja: angular.io/guide/static-query-migration
Stevethemacguy
17

Z kątowych dokumentów

static - czy rozstrzygać wyniki zapytania przed uruchomieniem wykrywania zmian (tj. zwracać tylko wyniki statyczne). Jeśli ta opcja nie zostanie podana, kompilator powróci do swojego domyślnego zachowania, polegającego na wykorzystaniu wyników zapytania w celu ustalenia czasu rozwiązania zapytania. Jeśli jakiekolwiek wyniki zapytania znajdują się w widoku zagnieżdżonym (np. * NgIf), zapytanie zostanie rozwiązane po uruchomieniu wykrywania zmian. W przeciwnym razie zostanie to rozwiązane przed uruchomieniem wykrywania zmian.

Lepszym rozwiązaniem może być użycie, static:truejeśli dziecko nie zależy od żadnych warunków. Jeśli widoczność elementu ulegnie zmianie, wówczas static:falsemoże dać lepsze wyniki.

PS: Ponieważ jest to nowa funkcja, może być konieczne uruchomienie testów wydajności.

Edytować

Jak wspomniał @Massimiliano Sartoretto, github commit może dać ci więcej informacji.

Sachin Gupta
źródło
3
Dodałbym oficjalne motywacje związane z tą funkcją github.com/angular/angular/pull/28810
Massimiliano Sartoretto
2

Przyszedł tutaj, ponieważ ViewChild był pusty w ngOnInit po aktualizacji do Angular 8.

Zapytania statyczne są wypełniane przed ngOnInit, natomiast zapytania dynamiczne (static: false) są wypełniane po. Innymi słowy, jeśli wizualizacja ma teraz wartość NULL w ngOnInit po ustawieniu static: false, należy rozważyć zmianę na static: true lub przenieść kod do ngAfterViewInit.

Zobacz https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

Pozostałe odpowiedzi są poprawne i wyjaśniają, dlaczego tak jest: zapytania zależne od dyrektyw strukturalnych, np. Odwołanie ViewChild wewnątrz ngIf, powinny być uruchamiane po rozwiązaniu warunku tej dyrektywy, tj. Po wykryciu zmiany. Można jednak bezpiecznie używać static: true, a tym samym rozwiązywać zapytania przed ngOnInit w przypadku nie odkrytych referencji. Imho ten konkretny przypadek zawiera wzmiankę o zerowym wyjątku, prawdopodobnie byłby to pierwszy sposób, w jaki napotkasz tę szczegółowość, tak jak było to dla mnie.

korona
źródło
1

wyświetl podrzędny @ prostokątny token 5+ dwa argumenty („nazwa lokalnego odwołania”, statyczny: false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

aby poznać różnicę między prawdą a fałszem, sprawdź to

static - czy rozstrzygać wyniki zapytania przed uruchomieniem wykrywania zmian (tj. zwracać tylko wyniki statyczne). Jeśli ta opcja nie zostanie podana, kompilator powróci do swojego domyślnego zachowania, polegającego na wykorzystaniu wyników zapytania w celu ustalenia czasu rozwiązania zapytania. Jeśli jakiekolwiek wyniki zapytania znajdują się w widoku zagnieżdżonym (np. * NgIf), zapytanie zostanie rozwiązane po uruchomieniu wykrywania zmian. W przeciwnym razie zostanie to rozwiązane przed uruchomieniem wykrywania zmian.

Samar Abdallah
źródło
0

W ng8 można ręcznie ustawić czas dostępu do komponentu potomnego w komponencie macierzystym. Ustawienie statyczne na true oznacza, że ​​komponent nadrzędny otrzymuje tylko definicję komponentu na przechwyceniu onInit: Np .:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

Jeśli static ma wartość false, to defgację otrzymujesz tylko w ngAfterViewInit (), w ngOnInit (), będziesz niezdefiniowany.

Tethys Zhang
źródło