Javascript

Kurs Angular 2 – Referencja lokalna

Referencja lokalna to kolejny mechanizm w Angular 2 umożliwiający komunikację pomiędzy komponentami. Dzięki niej, z poziomu rodzica jesteśmy w stanie uzyskać dostęp do dowolnego elementu znajdującego się w szablonie komponentu – zarówno podstawowego tagu, jak i komponentu „dziecka”.

Po co i kiedy?

W poprzednim artykule omawiałem komunikację uzyskiwaną dzięki parametrom @Input i @Output. W tamtym przypadku, to komponent decydował o udostępnianiu odpowiedniego interfejsu służącego do komunikacji. To nie zawsze jest wystarczające rozwiązanie.

Jak to osiągnąć?

Czasami chcielibyśmy uzyskać dostęp do komponentu, który nie dał nam takiej możliwości lub do zwykłego tagu – np. input w celu ręcznego wyłuskania wartości. Jednym z rozwiązań jest właśnie referencja lokalna. Utworzenie referencji lokalnej jest niezwykle proste. Wystarczy, że w szablonie komponentu oznaczymy interesujący nas element w taki sposób:


<add-todo (addTodo)="addTodo($event)" #addTodoRef></add-todo>

Oczywiście – tak jak wspomniałem wcześniej – nic nie stoi na przeszkodzie, aby uzyskać dostęp do dowolnego, podstawowego tagu:


<h2 #ref>Todo App</h2>

To wszystko. Teraz powstaje pytanie – w jaki sposób dostać się do tego z poziomu klasy komponentu?

@ViewChild

Aby w klasie dostać się do zadeklarowanej referencji, wykorzystujemy adnotację @ViewChild w następujący sposób:


@ViewChild('ref') ref: ElementRef;

Jak możemy zauważyć, referencje wskazujące na podstawowe tagi mają typ ElementRef. Z komponentami jest zupełnie inaczej:


@ViewChild('addTodoRef') addTodoRef: AddTodoComponent;

Typ jest równoważny klasie komponentu, dzięki czemu mamy swobodny dostęp do publicznych składowych (np. możemy z poziomu rodzica wywołać metodę dziecka). Pozostaje pytanie – czy nie da się tego zrobić w bardziej elegancki sposób?

Owszem, da się. Dekorator @ViewChild ma jeszcze jedną, interesującą umiejętność. Jest w stanie wskazać komponent na podstawie typu, toteż powyższy zapis możemy przekształcić w następujący:


@ViewChild(AddTodoComponent) addTodoRef: AddTodoComponent;

Dzięki czemu nie musimy zaśmiecać kodu szablonu zbędnymi referencjami.

Uwaga! Dostęp do obiektów oznaczonych adnotacją @ViewChild mamy dopiero przy wystąpieniu zdarzenia cyklu życia komponentu ngAfterViewInit.

Więcej dzieci tego samego typu

Wiemy już w jaki sposób dostać się do pojedynczego elementu. Wyobraźmy sobie, że nasz komponent zawiera przykładowo 10 komponentów dzieci tego samego typu (np. TodoItemComponent). W jaki sposób dostać się do nich wszystkich? Przy pomocy adnotacji @ViewChildren:


@ViewChildren(TodoItemComponent) todosRefsList: QueryList<TodoItemComponent>;

W rezultacie w zmiennej todosRefsList odnajdziemy pełną kolekcję QueryList, udostępniającą garść pożytecznych metod, z którymi warto się zapoznać.

ContentChild(ren)

Zarówno @ViewChild jak i @ViewChildren nie mają dostępu do fragmentów transkludowanych szablonu.

W takim przypadku musimy skorzystać z odpowiedników – adnotacji @ContentChild i @ContentChildren. Sposób działania jest taki sam, z tym, że elementy dostępne są dopiero od momentu wystąpienia zdarzenia cyklu życia komponentu ngAfterContentInit.

Podsumowanie

Dzisiaj omówiłem kolejny sposób umożliwiający komunikację pomiędzy komponentami. W następnym artykule zajmiemy się tematem serwisów, ponieważ są one ściśle związane z ostatnim z podstawowych typów komunikacji.