Kurs Angular · Moduł 5: Serwisy i DI
Komunikacja Między Komponentami przez Serwisy
W tej lekcji2
Serwisy są doskonałym sposobem na komunikację między komponentami - jak gońcy między zamkami.
Przykład: Shared State Service
import { Injectable, signal, computed } from '@angular/core';
export interface CartItem {
id: number;
name: string;
quantity: number;
price: number;
}
@Injectable({ providedIn: 'root' })
export class CartService {
// Stan jako signals
private items = signal<CartItem[]>([]);
// Computed values
readonly cartItems = this.items.asReadonly();
readonly totalItems = computed(() =>
this.items().reduce((sum, item) => sum + item.quantity, 0)
);
readonly totalPrice = computed(() =>
this.items().reduce((sum, item) => sum + item.price * item.quantity, 0)
);
addItem(item: Omit<CartItem, 'quantity'>): void {
const existing = this.items().find(i => i.id === item.id);
if (existing) {
this.items.update(items =>
items.map(i => i.id === item.id
? { ...i, quantity: i.quantity + 1 }
: i
)
);
} else {
this.items.update(items => [...items, { ...item, quantity: 1 }]);
}
}
removeItem(id: number): void {
this.items.update(items => items.filter(i => i.id !== id));
}
clearCart(): void {
this.items.set([]);
}
}Użycie w Komponentach
// header.component.ts - wyświetla ilość
@Component({
template: `<span>{{ cartService.totalItems() }}</span>`
})
export class HeaderComponent {
cartService = inject(CartService);
}
// product.component.ts - dodaje do koszyka
@Component({
template: `<button (click)="addToCart()">Dodaj</button>`
})
export class ProductComponent {
private cartService = inject(CartService);
addToCart(): void {
this.cartService.addItem({
id: this.product.id,
name: this.product.name,
price: this.product.price
});
}
}Hasła z dokumentacji w tej lekcji
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. W jaki sposób, według lekcji, komponenty mogą komunikować się i współdzielić stan?
2. Której funkcji użyjesz w serwisie, aby utworzyć wartość pochodną liczoną automatycznie z innych signali?
To 2 z 4 pytań do tej lekcji. Pozostałe rozwiążesz w grze.
Zadania praktyczne w grze
- Klikanie w kolejności
Zbuduj wyrażenie udostępniające sygnał tylko do odczytu (klikaj po kolei):
- Edytor kodu
Uzupełnij serwis komunikacyjny używający Signals do współdzielenia stanu.
- Klikanie w kolejności
Zbuduj wywołanie czyszczące stan koszyka przez ustawienie pustej tablicy (klikaj po kolei):
- Układanie w pionie
Uporządkuj kolejność operacji na serwisie koszyka opartym o signals:
- Układanie w poziomie
Ułóż odczyt sygnału totalItems z serwisu w szablonie (jedna linia, bez nawiasów {{ }}):
- Układanie w pionie
Uporządkuj budowę komponentu korzystającego ze wspólnego serwisu CartService: