Kurs Angular · Moduł 6: Signals
Wejścia na sygnałach - jak samuraj przyjmuje rozkazy
W tej lekcji3
Komponent-karta samuraja dostaje dane od rodzica: imię, poziom, klan. Kiedyś przyjmował je przez @Input(), dziś przez sygnały. Ta lekcja pokazuje trzy rodzaje takich wejść: zwykłe input() (rozkaz w jedną stronę), model() (rozmowa w dwie strony) i sygnałowe zapytania o dzieci. Wszystkie łączy jedno - odczytujesz je jak każdy inny sygnał, przez ().
input() - rozkaz z góry
input() zamienia dane od rodzica w sygnał tylko do odczytu. W szablonie czytasz go jak zwykły sygnał: name().
import { Component, input } from '@angular/core';
@Component({
selector: 'app-samurai-card',
template: `<h2>{{ name() }}</h2><p>Poziom: {{ level() }}</p>`
})
export class SamuraiCardComponent {
name = input('Unknown'); // opcjonalny, z domyslna wartoscia
level = input.required<number>(); // wymagany
clan = input('Ronin', {
transform: (v: string) => v.toUpperCase() // przeksztalc przy wejsciu
});
}Trzy warianty pokrywają większość potrzeb. input('Unknown') ma wartość domyślną, gdy rodzic nic nie poda. input.required<number>() przeciwnie - Angular zgłosi błąd, jeśli rodzic zapomni go przekazać, co chroni przed cichą pomyłką. A transform przepuszcza wartość przez funkcję już na wejściu - tu każdy klan zapisujesz wielkimi literami, bez ręcznego przetwarzania w komponencie. Rodzic używa ich jak zawsze: <app-samurai-card name="Musashi" [level]="10">.
model() - rozmowa w dwie strony
Czasem dziecko ma nie tylko czytać wartość, ale i ją zmieniać - jak suwak zdrowia. Kierunki są trzy: input() przekazuje dane od rodzica do dziecka, output() wysyła zdarzenie od dziecka do rodzica (deklarujesz je jako selected = output<string>() i wywołujesz selected.emit(...)), a model() łączy oba w dwukierunkowe wiązanie: rodzic podaje wartość, dziecko ją aktualizuje, a rodzic widzi zmianę.
import { Component, model } from '@angular/core';
@Component({
selector: 'app-health-bar',
template: `
<input type="range" [value]="health()"
(input)="health.set(+$any($event.target).value)">
`
})
export class HealthBarComponent {
health = model(100); // dziala jak [(ngModel)]
}Różnica względem input() jest jedna, ale zasadnicza: model() można ustawiać (health.set(...)), a zmiana wraca do rodzica. Dlatego rodzic wiąże go dwustronnie: <app-health-bar [(health)]="currentHealth">. Gdy przesuniesz suwak w dziecku, currentHealth w rodzicu zmieni się samo. To sygnałowy odpowiednik dawnego [(ngModel)].
Sygnałowe zapytania o dzieci
Ostatni rodzaj wejść to nie dane od rodzica, lecz uchwyty do własnych dzieci w szablonie. Dawne dekoratory @ViewChild mają teraz sygnałowe wersje.
import { viewChild, viewChildren, contentChild } from '@angular/core';
export class ParentComponent {
childComponent = viewChild(ChildComponent); // jedno dziecko z szablonu
allCards = viewChildren(CardComponent); // wszystkie takie dzieci
projectedHeader = contentChild('header'); // dziecko wrzucone przez <ng-content>
}Nazwy mówią, gdzie szukać: viewChild znajduje element z własnego szablonu komponentu, a contentChild - element wrzucony z zewnątrz przez projekcję treści. Liczba mnoga (viewChildren) zwraca wszystkie pasujące. Zysk z wersji sygnałowej jest ten sam co wszędzie: wynik to sygnał, więc możesz na nim budować computed i effect, zamiast czekać na zdarzenia cyklu życia.
Pamiętaj z tej lekcji jedną wspólną cechę: wszystkie te wejścia to sygnały, które czytasz przez (). input() przyjmuje rozkaz z góry, model() prowadzi rozmowę w dwie strony, a viewChild/contentChild dają sygnałowe uchwyty do dzieci.
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Jak zdefiniować wymagany signal input?
2. Która funkcja tworzy property wspierającą two-way binding [(value)] w komponencie standalone?
To 2 z 3 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Układanie w poziomie
Ułóż w jednej linii deklarację property two-way binding health z wartością początkową 100.
- Układanie w poziomie
Ułóż w jednej linii deklarację opcjonalnego signal inputu name z wartością domyślną 'Unknown'.
- Edytor kodu
Uzupełnij kartę samuraja: imię ma przychodzić od rodzica jako wejście sygnałowe (nowe API zamiast dekoratora @Input), a wybór wraca do rodzica przez output().
- Klikanie w kolejności
Ułóż wywołanie tworzące wymagany input typu number (część po znaku =).