AngularAtlased. 22.2

Cap. 02Fundamente moderne06 / 75

Data binding și evenimente

Interpolare, binding pe proprietăți și pe atribute, evenimente cu $event și filtre de taste și cum e construit [( )] — ce intră în DOM și ce se întoarce.

Un template nu e HTML static: Angular îl ține legat de clasa componentei. Parantezele îți spun în ce direcție merg datele — {{ }} și [ ] duc valori din clasă în DOM, ( ) aduce evenimente înapoi în clasă, iar [( )] face amândouă.

Cele mai multe bug-uri de începător de aici nu sunt erori de sintaxă. Vin din trei întrebări: în ce direcție curg datele, setez o proprietate DOM sau un atribut HTML și ce element a primit de fapt click-ul?

De ce contează
Fiecare ecran pe care îl construiești e făcut din aceste patru binding-uri. Când știi exact ce scrie fiecare și când, un câmp care nu se resetează, un buton care rămâne dezactivat sau un click care deschide altceva nu mai sunt mistere.

Patru binding-uri, două direcții

Datele coboară cu {{ }} și [ ], evenimentele urcă cu ( ). Angular reevaluează expresiile din dreapta când se schimbă signal-urile pe care le citesc și scrie în DOM doar dacă rezultatul diferă de ce a scris data trecută.

SintaxăDirecțieCe se întâmplă
{{ expr }}clasă → DOMsetează textul unui nod (mereu text, niciodată HTML)
[prop]="expr"clasă → DOMsetează o proprietate a elementului DOM
[attr.x]="expr"clasă → DOMsetează sau scoate un atribut HTML
(event)="stmt"DOM → clasărulează o instrucțiune când apare evenimentul
[(x)]="sig"în ambele sensuriun property binding plus un eveniment de schimbare, într-unul singur
<!-- clasă → DOM -->
<h2>{{ title() }}</h2>                          <!-- interpolare: text -->
<img [src]="avatarUrl()" [alt]="userName()" />  <!-- property binding -->
<td [attr.colspan]="wide() ? 2 : null"></td>    <!-- attribute binding -->

<!-- DOM → clasă -->
<button (click)="save()">Salvează</button>      <!-- event binding -->

<!-- în ambele sensuri -->
<app-rating [(value)]="stars" />                <!-- two-way binding -->

Interpolarea: mereu text

{{ }} transformă valoarea în string și o pune într-un nod de text. HTML-ul din valoare apare ca simple caractere, nu e interpretat — asta te protejează de XSS. Signal-urile se citesc apelându-le: {{ count() }}. Ține expresia ieftină și fără efecte secundare: poate rula la fiecare trecere de change detection.

<!-- valoarea devine text: '<b>Ana</b>' apare cu tot cu paranteze, nu îngroșat -->
<p>Salut, {{ userName() }}!</p>

<!-- orice expresie fără efecte secundare; signal-urile se apelează -->
<p>{{ items().length }} produse · {{ total() | currency: 'EUR' }}</p>
<p>{{ user()?.address?.city ?? 'încă fără oraș' }}</p>

<!-- ✗ textul funcției signal-ului, nu valoarea lui -->
<p>{{ count }}</p>

Property binding setează o proprietate DOM

[value]="name()" nu atinge HTML-ul. Setează proprietatea value a elementului input. Atributele sunt valorile de pornire scrise în HTML; proprietățile sunt starea vie a elementului. Când utilizatorul tastează, proprietatea se schimbă, iar atributul rămâne cum era. Iar Angular scrie proprietatea doar când se schimbă name() — deci dacă în clasă e tot aceeași valoare, un reset nu schimbă ce a tastat utilizatorul.

@Component({
  selector: 'app-profile',
  template: `
    <!-- setează input.value; nu schimbă atributul value="" -->
    <input [value]="name()" (input)="name.set(box.value)" #box />
    <button [disabled]="saving()" (click)="save()">Salvează</button>
    <button (click)="reset()">Resetează</button>
  `,
})
export class Profile {
  readonly name = signal('Ana');
  readonly saving = signal(false);

  reset() {
    // merge doar pentru că (input) ține name() la zi;
    // doar cu [value], name() e tot 'Ana' și set('Ana') nu schimbă nimic
    this.name.set('Ana');
  }
}
LiveProprietate sau atribut și un reset care nu resetează
name()în clasă'Ana'
input.valueproprietate DOM'Ana'
getAttribute('value')atribut HTMLnull

sincronizatȘi câmpul, și signal-ul spun 'Ana'.

Atribut static sau property binding
click-uri: 0

Primul buton e dezactivat: atributul există, iar valoarea lui text nu contează.

În modul [value]: tastează un nume de familie după „Ana”, apoi apasă name.set('Ana'). Repetă în al doilea mod și compară tabelul și cele două butoane de sub el.

În primul mod, câmpul arată un text despre care clasa nu știe nimic. name.set('Ana') îi dă signal-ului valoarea pe care o avea deja, deci nu se schimbă nimic și Angular nu scrie în input. Să citești înapoi input-ul cu (input) — sau să legi în ambele sensuri cu [( )] ori cu un formular — ține clasa și DOM-ul în pas. Observă că getAttribute('value') rămâne tot timpul null: Angular n-a setat niciodată atributul.

Când nu există proprietate: [attr.]

Unele atribute nu au o proprietate corespunzătoare: aria-*, colspan, data-*, atributele de pe SVG. Pentru ele folosești [attr.nume]. O valoare null sau undefined scoate atributul — așa pornești și oprești aria-current. Clasele și stilurile au binding-urile lor, explicate în [class] și [style].

Atributele booleene sunt capcana clasică: browserul se uită doar dacă atributul există. disabled="false" e un string, atributul e prezent, iar butonul e dezactivat. [disabled]="false" setează proprietatea la booleanul false.

<!-- pentru acestea nu există proprietate DOM: legi atributul -->
<td [attr.colspan]="span()">…</td>
<svg><circle [attr.r]="radius()" /></svg>
<div [attr.data-state]="state()"></div>

<!-- null scoate atributul: aria-current există doar pe link-ul activ -->
<a [attr.aria-current]="active() ? 'page' : null" href="/orders">Comenzi</a>

<!-- ✗ atributul există, deci butonul e dezactivat -->
<button disabled="false">Salvează</button>
<!-- ✓ proprietatea primește booleanul false -->
<button [disabled]="false">Salvează</button>

Event binding: ( )

(click)="save()" adaugă un listener pe element și rulează instrucțiunea când apare evenimentul. $event e obiectul evenimentului DOM: un MouseEvent pentru click-uri, un KeyboardEvent pentru taste sau valoarea emisă de un output() al unei componente. Ca să citești un câmp, o referință de template precum #box e mai simplă și complet tipată: (input)="name.set(box.value)".

<button (click)="save()">Salvează</button>

<!-- $event e evenimentul DOM; pentru un output() e valoarea emisă -->
<div (pointermove)="track($event.clientX, $event.clientY)"></div>
<app-rating (valueChange)="stars.set($event)" />

<!-- o referință de template are tipul HTMLInputElement: fără cast-uri -->
<input #box (input)="query.set(box.value)" />

<!-- ✗ în modul strict: 'value' does not exist on type 'EventTarget' -->
<input (input)="query.set($event.target.value)" />

Evenimentele urcă (bubbling)

Un click pornește de pe cel mai adânc element și apoi urcă prin fiecare strămoș, rulând și handler-ele lor de (click). Așa ajunge un buton Șterge dintr-un rând clickabil să deschidă și rândul — handler-ul rândului rulează imediat după cel al butonului.

LiveUn buton Șterge într-un rând clickabil
  • Comanda #1042
  • Comanda #1043
  • Comanda #1044
Handler-ele care au rulat, în ordine

Niciun click încă.

Apasă Șterge la o comandă și uită-te la Detalii și la lista de handler-e. Apoi treci pe $event.stopPropagation() și încearcă din nou.

$event.target e elementul de pe care a pornit click-ul și e același în toate handler-ele. $event.currentTarget e elementul al cărui handler rulează acum. stopPropagation() în handler-ul interior e soluția rapidă. O structură mai bună e adesea să nu le imbrici deloc: acțiunea rândului devine un link sau un buton adevărat lângă Șterge, nu un handler de click pe tot rândul — așa îl pot deschide și cei care folosesc tastatura.

<ul>
  @for (order of orders(); track order.id) {
    <!-- rândul deschide comanda… -->
    <li (click)="open(order)">
      Comanda #{{ order.id }}
      <!-- …iar fără stopPropagation(), un click aici ajunge și la rând -->
      <button (click)="remove(order); $event.stopPropagation()">Șterge</button>
    </li>
  }
</ul>

<!-- adesea mai bine: două acțiuni separate, fără imbricare și accesibile din tastatură -->
<li>
  <a [routerLink]="['/orders', order.id]">Comanda #{{ order.id }}</a>
  <button (click)="remove(order)">Șterge</button>
</li>

Filtre de taste și acțiunea implicită a browserului

Angular te lasă să filtrezi evenimentele de tastatură direct în binding: (keydown.enter), (keydown.escape), (keydown.shift.enter), (keydown.control.s). Modificatorii trebuie să se potrivească exact: (keydown.enter) nu rulează la Shift+Enter. Handler-ul tău rulează înainte de acțiunea implicită a browserului — un rând nou, trimiterea formularului, urmarea unui link — iar $event.preventDefault() anulează acțiunea.

<textarea
  #msg
  [value]="draft()"
  (input)="draft.set(msg.value)"
  (keydown.enter)="send($event)"
  (keydown.escape)="draft.set('')"
></textarea>
<!-- (keydown.enter) nu rulează la Shift+Enter: browserul adaugă un rând, ca de obicei -->
LiveO casetă de chat: Enter trimite, Shift+Enter adaugă un rând
  • Niciun mesaj încă.
(keydown)—
(keydown.enter)—
(keydown.shift.enter)—
(keydown.escape)—

Apasă o tastă în caseta de mesaj.

Scrie un mesaj și apasă Enter în fiecare mod. Apoi încearcă Shift+Enter și Escape și urmărește ce binding-uri rulează.

Fără preventDefault(), browserul inserează rândul nou după ce handler-ul tău a golit draft, iar evenimentul (input) scrie textul înapoi. Încă un detaliu pe care majoritatea casetelor de chat îl greșesc: cât timp cineva scrie în japoneză sau chineză cu o metodă de introducere (IME), Enter confirmă caracterele. Verifică $event.isComposing și ignoră tasta în cazul ăsta.

[( )] înseamnă [ ] plus ( )

„Banana în cutie” e o prescurtare. [(value)]="name" înseamnă un property binding pe value plus un listener pentru evenimentul valueChange care scrie înapoi. Când dai un WritableSignal, Angular setează signal-ul în locul tău. În componentele tale, model() creează ambele jumătăți; pentru câmpuri de formular, folosește Signal Forms.

<!-- prescurtarea… -->
<app-rating [(value)]="stars" />

<!-- …înseamnă exact asta -->
<app-rating [value]="stars()" (valueChange)="stars.set($event)" />

<!-- cu un WritableSignal, Angular apelează set() în locul tău;
     copilul îl declară cu: value = model(0) -->

Variabile de referință în template

#nume pe un element îți dă elementul în restul template-ului; pe o componentă, îți dă instanța componentei. E cel mai rapid mod să citești un câmp sau să apelezi focus() fără să treci prin $event.target, al cărui tip e doar EventTarget. În clasă, aceeași referință o obții cu viewChild().

<!-- pe un element: elementul însuși -->
<input #search placeholder="Caută" />
<button (click)="search.focus()">Focus</button>

<!-- pe o componentă: instanța componentei -->
<app-video-player #player />
<button (click)="player.play()">Pornește</button>

<!-- în clasă: readonly search = viewChild<ElementRef<HTMLInputElement>>('search') -->

Obiceiuri bune / de evitat

Obiceiuri bune
  • Ține sursa de adevăr în clasă (un signal) și citește înapoi fiecare schimbare din DOM.
  • Folosește referințe de template (#box) în loc de $event.target când ai nevoie de o valoare.
  • Folosește [attr.] pentru aria-* și data-* și null ca să scoți un atribut.
De evitat
  • Funcții care fac muncă grea în {{ }} sau [ ] — rulează din nou la fiecare trecere.
  • Atribute booleene statice cu valoare (disabled="false"): contează doar prezența atributului.
  • stopPropagation() din obișnuință: ascunde evenimentul și de analytics, și de meniurile care se închid la click în afară, și de colegii tăi.

Capcane frecvente

  • Un reset care nu resetează. Câmpul era legat într-un singur sens, utilizatorul a tastat, iar clasa ține încă valoarea veche. Dacă o setezi din nou, nu se schimbă nimic.
  • Parantezele uitate. {{ count }} afișează funcția signal-ului, nu valoarea lui. Compilatorul te avertizează; nu ignora avertismentul.
  • Rândul se deschide când apeși Șterge. Click-ul a urcat de la buton la rând. Oprește-l sau nu imbrica acțiuni.
  • Un rând gol rămas după trimitere. Acțiunea implicită a lui Enter a rulat după handler. Apelează $event.preventDefault().
  • Scrii $event.target.value. target e un EventTarget, deci în modul strict nu compilează. Folosește o referință de template sau citește-l în clasă, cu un cast.

Fișă rapidă

{{ expr }}             text în DOM; HTML-ul e escapat; signal-urile se apelează: {{ count() }}
[prop]="expr"          o proprietate DOM (value, disabled, src, checked) sau un input de componentă
[attr.x]="expr"        un atribut HTML (aria-*, data-*, colspan, svg); null îl scoate
[class.x] / [style.x]  o clasă sau un stil; vezi pagina [class] și [style]
(event)="stmt"         un listener; $event = evenimentul DOM sau valoarea emisă
(keydown.enter)        filtre de taste; modificatorii trebuie să se potrivească: shift.enter, control.s, escape
[(x)]="sig"            [x]="sig()" + (xChange)="sig.set($event)"
#ref                   elementul sau instanța componentei, în template

când scrie Angular     doar când valoarea diferă de ultima scrisă
atribut vs proprietate atribut = valoarea de pornire din HTML; proprietate = starea vie
bubbling               un click rulează handler-ele fiecărui strămoș; target rămâne același
acțiuni implicite      rulează după handler-ul tău; $event.preventDefault() le anulează

Cap. 02 · 0 din 8 terminate

Ai terminat lecția?

Marcheaz-o și apare pe harta ta: în cuprins și pe prima pagină.

Se marchează singură după ce citești toată lecția.

  1. Standalone & bootstrap
  2. Data binding și evenimente
  3. Control flow: @if, @for, @switch
  4. @let și expresiile noi din template
  5. @defer — lazy loading în template
  6. Class & style bindings
  7. Stilurile componentelor și încapsularea
  8. Pipes: când și cum
Vezi toată harta ta

Toate cele 75 de pagini · scrie ca să filtrezi

  • 01Ce e nou în Angular 21 & 22Toate schimbările importante din v21 și v22, pe scurt, cu link către pagina care le explică.Start
  • 01Prima ta aplicație, pas cu pasO listă de lecturi construită de la o componentă goală la o aplicație terminată — signals, @for, input-uri și output-uri, un serviciu și un formular, pas cu pas.Start
  • 01Decizii rapide„Unde pun asta?”, „Signal sau Observable?”, „Shared sau feature?” — răspunsuri scurte la întrebările de zi cu zi.Start
  • 01Întrebări de interviu Angular60 de întrebări reale de interviu pentru junior, mid și senior, cu răspunsul de dat, întrebarea care urmează și greșelile de evitat. Plus o simulare de interviu.Start
  • 02Standalone & bootstrapCum pornește o aplicație fără NgModule: bootstrapApplication, app.config.ts, imports în componentă.Fundamente moderne
  • 02Data binding și evenimenteInterpolare, binding pe proprietăți și pe atribute, evenimente cu $event și filtre de taste și cum e construit [( )] — ce intră în DOM și ce se întoarce.Fundamente moderne
  • 02Control flow: @if, @for, @switchSintaxa de blocuri care înlocuiește *ngIf/*ngFor/ngSwitch, cu track, @empty și verificare exhaustivă.Fundamente moderne
  • 02@let și expresiile noi din templateVariabile locale cu @let, arrow functions, spread, regex, instanceof, comentarii în tag-uri.Fundamente moderne
  • 02@defer — lazy loading în templateÎncarci componente grele doar când e nevoie: triggere, prefetch, placeholder, loading, error.Fundamente moderne
  • 02Class & style bindingsDe ce [class.x] și [style.x] au înlocuit ngClass și ngStyle (cu migrare automată din v21).Fundamente moderne
  • 02Stilurile componentelor și încapsularea:host, cele trei moduri de încapsulare, teme cu variabile CSS și de ce ::ng-deep e ultima soluție.Fundamente moderne
  • 02Pipes: când și cumPipe pur vs impur, pipe custom și cum alegi între pipe, computed() și o metodă.Fundamente moderne
  • 03signal() și computed()Primitivele reactive: stare scriibilă, stare derivată, egalitate, untracked și reguli de imutabilitate.Signals & reactivitate
  • 03effect() — când DA, când NUEfecte secundare sincronizate cu semnale: localStorage, logging, API-uri imperative. Și capcanele lor.Signals & reactivitate
  • 03linkedSignal() — stare derivată editabilăUn semnal care se resetează când se schimbă sursa, dar pe care îl poți și seta manual.Signals & reactivitate
  • 03resource, rxResource, httpResourceDate asincrone ca semnale: status, value, error, reload, anulare automată. Stabile din v22.Signals & reactivitate
  • 03debounced() — semnale cu întârziereVarianta „debounce” a unui semnal, fără RxJS. Perfect pentru căutare.Signals & reactivitate
  • 03Liste: căutare, filtrare, sortare, paginareUn lanț de computed-uri care recalculează doar ce s-a schimbat, cu filtrele ținute în URL, ca un link să redeschidă aceeași vedere.Signals & reactivitate
  • 03Observables de la zeroCe e un Observable, subscribe și unsubscribe, operatorii pe care îi folosești în fiecare săptămână, cold vs hot — și când ajunge un signal.Signals & reactivitate
  • 03Signals ↔ RxJStoSignal, toObservable, takeUntilDestroyed, outputFromObservable — și când RxJS rămâne alegerea bună.Signals & reactivitate
  • 04input() și output()Inputuri ca semnale (required, transform, alias) și outputuri tipizate. Data down, events up.Componente: comunicare
  • 04model() — two-way bindingBanana-in-a-box [( )] cu un singur API. Când îl folosești și când e mai bine input + output.Componente: comunicare
  • 04viewChild & contentChildInterogări ca semnale: viewChild, viewChildren, contentChild, contentChildren, opțiunea read.Componente: comunicare
  • 04Lifecycle & DestroyRefCe hook-uri mai contează în era signals, afterNextRender, DestroyRef și ngOnChanges tipizat.Componente: comunicare
  • 04Content projectionng-content cu select, sloturi multiple, conținut implicit și capcana proiecției condiționale.Componente: comunicare
  • 04ng-template & ngTemplateOutletTemplate-uri ca valori: render props în Angular, context tipizat și personalizare de componente.Componente: comunicare
  • 05Smart vs DumbContainer vs presentational: cine ține starea, cine doar afișează, și cum le împarți corect.Design de componente
  • 05Componente generice <T>Un DataTable<T> sau Select<T> tipizat corect, cu template-uri pentru celule.Design de componente
  • 05Componente dinamiceNgComponentOutlet, createComponent cu inputBinding/outputBinding și un dashboard construit din config.Design de componente
  • 05Directive & host compositionDirective atribut, metadata host: {} și Directive Composition API (hostDirectives).Design de componente
  • 05Controale custom de formularFormValueControl (Signal Forms) vs ControlValueAccessor: un rating cu stele, în ambele variante.Design de componente
  • 05Change detectionOnPush e implicit din v22, zone.js lipsește din v21. Ce declanșează randarea și cum să nu te arzi.Design de componente
  • 06inject() & @Service()Noul decorator @Service() din v22, inject() vs constructor și contextul de injecție.Dependency Injection
  • 06Providers & ierarhia de injectoriRoot vs rută vs componentă, useClass/useValue/useFactory/useExisting și modificatorii optional/self/skipSelf.Dependency Injection
  • 06InjectionToken & provideX()Configurare tipizată, funcții provideFeature(), makeEnvironmentProviders și inițializatori.Dependency Injection
  • 06injectAsync() — servicii lazyÎncarci un serviciu greu abia când ai nevoie de el, cu prefetch la idle.Dependency Injection
  • 07Structura de folderecore / shared / features, ce intră în fiecare și cum arată un feature pe dinăuntru.Arhitectura aplicației
  • 07Shared vs featureCând muți o componentă în shared și (mai ales) când NU. Checklist concret.Arhitectura aplicației
  • 07Interfețe & modeleInterfață inline sau fișier separat? DTO vs model de domeniu, type vs interface, unde le pui.Arhitectura aplicației
  • 07State management cu signalsStore-uri simple pe semnale, facade, stare locală vs globală și când îți trebuie NgRx.Arhitectura aplicației
  • 07Style guide & namingConvențiile oficiale actuale: nume de fișiere fără sufixe, protected, readonly, ordinea membrilor.Arhitectura aplicației
  • 07Barrels, aliasuri & granițeindex.ts, path aliases, API public pe feature și reguli de dependență care se pot verifica automat.Arhitectura aplicației
  • 07Erori: @boundary & ErrorHandlerNoul bloc @boundary din v22.2, ErrorHandler global, erori HTTP și erori din resource.Arhitectura aplicației
  • 08Routing modern & lazy loadingloadComponent, rute copil, parametri ca input-uri și moștenirea parametrilor (default nou în v22).Routing
  • 08Guards & resolverscanActivate, canMatch, canDeactivate și resolve ca funcții, cu redirect prin UrlTree / RedirectCommand.Routing
  • 09Signal Forms — bazeleFormulare construite pe semnale: form(), [formField], validare prin schemă. Stabile din v22.Formulare
  • 09Signal Forms — avansatValidare custom și cross-field, async/HTTP cu debounce, liste dinamice, disabled/hidden, scheme reutilizabile.Formulare
  • 09Reactive Forms tipizateFormGroup tipizat, nonNullable, FormArray — și cum conviețuiesc cu Signal Forms.Formulare
  • 10HttpClient, interceptors & API layerHttpClient fără setup (v21), Fetch implicit (v22), interceptori funcționali și stratul de API cu mapare DTO.HTTP & date
  • 11Performanță — checklistCe chiar contează: OnPush + signals, track, @defer, lazy routes, imagini, bundle și hidratare.Calitate & performanță
  • 11Testare cu VitestVitest e runner-ul implicit din v21. TestBed, componente cu semnale, servicii, HTTP și harness-uri.Calitate & performanță
  • 11DevTools: cum te uiți în aplicațieChrome DevTools și Angular DevTools pas cu pas: ce arată fiecare panou, cu exerciții care merg chiar pe site-ul ăsta.Calitate & performanță
  • 11Angular AriaComponente headless, accesibile, pe care le stilizezi cum vrei: tabs, accordion, menu, listbox...Calitate & performanță
  • 12SSR, prerender & render modesCând randezi pe server, când la build și când doar în browser: RenderMode pe rută, app.routes.server.ts și costurile reale.SSR & hidratare
  • 12Hidratare: event replay & incrementalCum preia browserul HTML-ul de pe server fără să-l refacă: hidratare completă, event replay, @defer (hydrate on …) și erorile de nepotrivire.SSR & hidratare
  • 12Cod compatibil cu serverulwindow nu există pe server: PLATFORM_ID, afterNextRender, DOCUMENT, TransferState, cache-ul HTTP și PendingTasks.SSR & hidratare
  • 13Micro frontendsCând merită să spargi o aplicație în mai multe deploy-uri și când e doar complexitate: Native Federation, Module Federation, iframes, Web Components.Arhitectură la scară
  • 13Web Components cu Angular ElementscreateCustomElement: o componentă Angular folosită ca tag HTML oriunde, plus comunicarea între aplicații prin evenimente și BroadcastChannel.Arhitectură la scară
  • 13Monorepo, librării & granițeUn workspace cu mai multe aplicații și librării: ng generate library, Nx, entry points secundare, publicare și reguli de dependență.Arhitectură la scară
  • 13Arhitectură hexagonală (ports & adapters)Domeniul fără Angular, porturi ca clase abstracte și adaptoare interschimbabile: HTTP, localStorage sau in-memory, fără să atingi UI-ul.Arhitectură la scară
  • 14Semnalele pe dinăuntruGraful reactiv: producători și consumatori, push-pull, de ce computed e lazy și glitch-free, problema diamantului și când rulează efectele.Reactivitate avansată
  • 14RxJS avansat: operatori de ordin superiorswitchMap, mergeMap, concatMap și exhaustMap pe o diagramă live, plus retry cu backoff, shareReplay și cum eviți scurgerile.Reactivitate avansată
  • 14NgRx SignalStoreState management la scară pe semnale: withState, withComputed, withMethods, rxMethod, entități și hooks — și când un store simplu e suficient.Reactivitate avansată
  • 14Mașini de stări cu signalsFără stări imposibile: o mașină tipizată pe signals, cu tranziții, guards și diagrama stărilor, live.Reactivitate avansată
  • 15WebSockets: timp real care rezistă rețeleiUn socket tipizat ca signals: reconectare cu backoff și jitter, heartbeat, coadă de mesaje cât ești offline și siguranță la SSR.Timp real și offline
  • 15Actualizări optimiste și rollbackInterfață instantanee, dar onestă: snapshot și rollback, răspunsuri sosite în altă ordine, chei de idempotență.Timp real și offline
  • 15Offline-first: Service Worker și cacheService Worker-ul Angular: strategii de cache, anunțarea versiunilor noi și o coadă pentru modificările făcute offline.Timp real și offline
  • 16Web WorkersCalcule grele fără să blochezi interfața: un worker real în pagină, comunicare prin mesaje și când nu merită.UI & performanță avansată
  • 16Liste uriașe: virtual scroll100.000 de rânduri fără lag: CDK virtual scroll, itemSize, trackBy și alternativele (paginare, infinite scroll).UI & performanță avansată
  • 16Animații moderne & View Transitionsanimate.enter și animate.leave în locul @angular/animations (depreciat), tranziții CSS și View Transitions la navigare.UI & performanță avansată
  • 16Memory leaks: cum le găsești și le repariSubscripții, timere și listeneri care trăiesc mai mult decât componenta lor — cum îi vezi în DevTools și cum îi închizi.UI & performanță avansată
  • 17Securitate: XSS, sanitizare & CSPCe face Angular automat împotriva XSS, când devine periculos bypassSecurityTrust, plus CSP cu nonce, Trusted Types și XSRF.Securitate & globalizare
  • 17Autentificare: token-uri & refreshUn interceptor care atașează token-ul, reîmprospătează o singură dată la 401 și reia cererile din coadă — plus unde ții token-ul.Securitate & globalizare
  • 17OAuth 2.1 și OpenID Connect cu PKCEFluxul authorization code cu PKCE, pas cu pas: verifier și challenge, state și nonce, ID token-ul și de ce un BFF e mai sigur.Securitate & globalizare
  • 17Internaționalizare (i18n)$localize, atributul i18n, ICU plural/select, build per limbă vs. traduceri la runtime și formatarea după locale.Securitate & globalizare