Cel mai rapid mod de a învăța Angular e să construiești ceva mic, de la cap la coadă. Pe pagina asta construiești o listă de lecturi: pornești de la o componentă care arată trei titluri și ajungi la o aplicație care îți păstrează cărțile între vizite. Fiecare pas adaugă o singură idee și trimite la pagina care o explică pe larg.
În laborator, aplicația din stânga rulează codul din dreapta. Citește codul, joacă-te cu aplicația, apoi treci la pasul următor.
Creează proiectul
Angular CLI creează proiectul, generează fișiere și pornește un server de dezvoltare care reîncarcă pagina de fiecare dată când salvezi. Proiectele noi din v22 folosesc componente standalone, signals și nu mai au Zone.js — exact ce folosește pagina asta.
npm install -g @angular/cli
ng new reading-list # componente standalone, zoneless și signals, implicit
cd reading-list
ng generate component reading-list
ng serve # http://localhost:4200Construiește-o în șase pași
Fiecare pas e o componentă reală. Schimbă ceva în aplicația live, apoi uită-te în cod și găsește rândul care a făcut asta.
O componentă e o clasă plus un template. Starea e un signal cu trei cărți, iar @for desenează câte un rând pentru fiecare carte.
Cărțile mele
- Frankenstein
- Dracula
- Moby-Dick
import { Component, signal } from '@angular/core';
interface Book {
id: number;
title: string;
read: boolean;
}
@Component({
selector: 'app-reading-list',
template: `
<h3>Cărțile mele</h3>
<ul>
<!-- track: cum deosebește Angular rândurile -->
@for (book of books(); track book.id) {
<li>{{ book.title }}</li>
}
</ul>
`,
})
export class ReadingList {
// starea: un signal care ține o listă
protected readonly books = signal<Book[]>([
{ id: 1, title: 'Frankenstein', read: true },
{ id: 2, title: 'Dracula', read: false },
{ id: 3, title: 'Moby-Dick', read: false },
]);
}Ce ai folosit
| Pas | Concepte | Citește mai mult |
|---|---|---|
| 1. Arată o listă | o componentă, signal(), @for cu track | Signals · Control flow |
| 2. Adaugă cărți | [value], (input), (keydown.enter), update() | Data binding |
| 3. Marchează ca citit | computed(), @if, @empty | Signals · Control flow |
| 4. Împarte în componente | input.required(), output() | input() și output() |
| 5. Mută starea într-un serviciu | @Service(), inject(), asReadonly() | Servicii |
| 6. Salvează și filtrează | effect(), localStorage, un filtru ca computed | effect() · Liste · Cod sigur pentru SSR |
Patru bug-uri pe care le scrie toată lumea o dată
Sunt bug-urile care apar în aproape orice primă aplicație Angular. Pornește-le pe rând, vezi simptomul cu ochii tăi, apoi citește de ce se întâmplă.
- Frankenstein
- Dracula
- Moby-Dick
Încearcă: apasă Adaugă „Hamlet” cu bug-ul pornit. Lista arată patru cărți, dar computed-ul și componenta OnPush spun tot trei. Resetează repară totul dintr-odată.
De ce: push() schimbă array-ul pe care signal-ul îl ține deja. Signal-ul compară referințe, vede același array și nu anunță pe nimeni; lista pare corectă doar pentru că click-ul a randat din nou această componentă. Dă-i signal-ului un array nou: update((list) => [...list, book]).
// ✗ același array, schimbat pe loc: signal-ul vede aceeași referință și nu anunță pe nimeni
this.books().push(book);
// ✓ un array nou: signal-ul îi anunță pe toți cei care îl citesc
this.books.update((list) => [...list, book]);Toate patru au aceeași rădăcină: Angular are încredere în ce îi spui. Un signal are încredere că o valoare nouă înseamnă o referință nouă, track are încredere în cheia ta, iar un computed are încredere că doar calculează. Ține-ți promisiunile și framework-ul face restul.
Unde mergi mai departe
- O pagină pentru fiecare carte, cu propriul URL: routing.
- Un formular adevărat, cu validare, pentru adăugarea cărților: Signal Forms.
- Cărți încărcate de pe un server: HttpClient și resource().
- Teste pentru store și pentru componente: testare.
- Unde pui fișierele când crește aplicația: structura folderelor.