AngularAtlased. 22.2

Cap. 12SSR & hidratare55 / 75

Hidratare: event replay & incremental

Cum preia browserul HTML-ul de pe server fără să-l refacă: hidratare completă, event replay, @defer (hydrate on …) și erorile de nepotrivire.

v22stabil ~0 min de citit Documentația oficială

Când pagina vine randată de pe server (SSR sau prerender), browserul are deja DOM-ul complet. Fără hidratare, Angular ar porni ca într-o aplicație CSR: ar arunca acel DOM și l-ar construi din nou — clipire vizibilă, LCP stricat, layout shift. Hidratarea înseamnă că Angular parcurge DOM-ul existent, îl potrivește cu arborele de componente și îl refolosește: leagă binding-urile și atașează listenerii la nodurile care există deja.

Peste ea s-au construit două optimizări: event replay — click-urile făcute înainte de hidratare nu se pierd — și hidratarea incrementală — bucăți din pagină rămân HTML static, fără JS descărcat, până când chiar e nevoie de ele.

Pe scurt
  • Hidratarea refolosește HTML-ul trimis de server în loc să-l recreeze, deci pagina nu clipește la pornire.
  • Event replay ține minte click-urile făcute înainte să se încarce JavaScript-ul și le rulează după.
  • Hidratarea incrementală (@defer cu hydrate on …) lasă părți din pagină neinteractive până când e nevoie de ele. Codul lor se descarcă abia atunci.
  • HTML-ul de pe server și cel din browser trebuie să fie identice. Altfel apar erori de nepotrivire, cu coduri de tip NG05xx.
  • ngSkipHydration e ieșirea de urgență pentru o componentă care modifică DOM-ul direct.
Ce s-a schimbat în v22
  • provideClientHydration() pornește implicit hidratarea incrementală, iar ea activează automat event replay.
  • withIncrementalHydration() e deprecated (eliminare planificată în v24) — scoate-l din config, e deja implicit.
  • Opțiunea nouă de opt-out e withNoIncrementalHydration().

Ce face hidratarea, pas cu pas

Pe server, după randare, Angular adnotează HTML-ul ca să poată fi „regăsit” mai târziu: atributul ngh pe gazda fiecărei componente (un index în datele de hidratare), comentarii-ancoră pentru @if/@for/@defer, un comentariu HTML nghm ca marcaj de integritate, jsaction pe elementele care au listeneri și un <script id="ng-state"> cu datele de hidratare (__nghData__) și răspunsurile HTTP din transfer cache.

@Component({
  selector: 'app-product-card',
  template: `
    <h2>{{ product().name }}</h2>
    @if (product().stock > 0) {
      <button (click)="addToCart()">Adaugă în coș</button>
    }
  `,
})
export class ProductCard {
  readonly product = input.required<Product>();
  addToCart() { /* ... */ }
}

În browser, la bootstrap, Angular nu mai creează noduri: le caută pe cele existente, folosind adnotările. Pentru fiecare nod verifică tipul și tag-ul (nu și textul) și atașează listenerii. Un text diferit nu e eroare — e pur și simplu suprascris la primul change detection.

După ce aplicația devine stabilă (fără request-uri HTTP și PendingTasks în curs), urmează etapa de final: Angular șterge nodurile de pe server pe care nu le-a revendicat nimeni, reia evenimentele din coadă și oprește transfer cache-ul. De aceea o aplicație care nu devine stabilă are efecte vizibile chiar dacă DOM-ul a fost refolosit corect.

Fără hidratareHidratare completăHidratare incrementală
DOM-ul serveruluiaruncat și recreatrefolositrefolosit
JS necesar la porniretottotdoar pentru ce e în afara blocurilor @defer (hydrate …)
Când devine interactiv un blocdupă re-randarela bootstrap, toată pagina odatăla trigger-ul blocului
Click-uri înainte de JSpierdutereluate doar cu withEventReplay()reluate; un click pe un bloc deshidratat îl hidratează

provideClientHydration și opțiunile

Dacă ai adăugat SSR cu ng add @angular/ssr, provider-ul e deja în app.config.ts. Fără argumente, în v22, primești setul recomandat:

import { ApplicationConfig } from '@angular/core';
import { provideClientHydration } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
  providers: [
    // v22, fără argumente:
    //  ✓ hidratare non-distructivă (refolosește DOM-ul serverului)
    //  ✓ HTTP transfer cache (GET/HEAD făcute pe server nu se repetă în browser)
    //  ✓ hidratare incrementală (@defer cu hydrate …) — include event replay
    //  ✓ în dev mode: provideStabilityDebugging()
    provideClientHydration(),
  ],
};
// app.config.server.ts face mergeApplicationConfig(appConfig, serverConfig),
// deci provider-ul ajunge și pe server — obligatoriu, altfel apare NG0505.
FuncțieCe faceÎn v22
provideClientHydration()hidratare non-distructivă + HTTP transfer cache + hidratare incrementală (cu event replay)setul implicit
withNoIncrementalHydration()oprește hidratarea incrementală (și, odată cu ea, event replay)nou în v22
withEventReplay()event replay fără hidratare incrementalăinclus implicit; explicit doar cu opt-out-ul de mai sus
withI18nSupport()hidratează și componentele cu blocuri i18n; fără el sunt re-randate de la zeroopțional
withHttpTransferCacheOptions({…})configurează ce răspunsuri ajung în HTML: filter, includeHeaders, includePostRequests, includeRequestsWithAuthHeaders…opțional
withNoHttpTransferCache()oprește transfer cache-ul: fiecare GET se face de două oriopțional
withIncrementalHydration()pornea hidratarea incrementalădeprecated din v22 (eliminare planificată în v24)

Provider-ul trebuie să existe și în config-ul de server — app.config.server.ts generat de CLI face mergeApplicationConfig(appConfig, serverConfig), deci e acolo automat. Dacă lipsește, serverul nu adnotează HTML-ul, iar în browser pagina e re-randată de la zero (în dev mode, cu avertismentul NG0505). Combinațiile contradictorii (de exemplu withNoHttpTransferCache() cu withHttpTransferCacheOptions()) aruncă eroarea NG05001 în dev mode.

Event replay

Problema: HTML-ul de pe server e vizibil cu mult înainte să sosească JS-ul (în timeline-ul de pe pagina SSR e banda galbenă). Utilizatorul vede un buton și apasă — dar butonul nu are încă niciun listener.

Mecanismul se bazează pe JSAction, o bibliotecă de event delegation integrată în Angular:

  1. Marcare — la serializare, serverul pune jsaction="click:;" pe fiecare element care are un listener în template.
  2. Captare — un script mic, inline, injectat imediat după <body> (event contract), ascultă la nivelul body tipurile de evenimente folosite în pagină și le ține în memorie.
  3. Reluare — după hidratare, când aplicația devine stabilă, Angular trimite evenimentele din coadă, în ordine, handler-elor reale.

Funcționează pentru evenimente native ale browserului (click, mouseover, focusin etc.). Cu hidratarea incrementală, contractul rămâne activ și după hidratare, ca să prindă evenimentele din blocurile încă deshidratate.

LiveEvent replay: click-uri înainte de hidratare (simulare)
magazin.ro/produse/42hidratat · interactiv
Căști wireless Aria X2
349 lei
Coș: 0Favorite: 0
main.js · executat
Coada event contract-ului (în memorie)
goală
  • Apasă „Reîncarcă pagina”, apoi dă click pe butoane cât timp bara de JS nu e plină.
Înainte de hidratare: 0 click-uri · reluate 0 · pierdute 0
Apasă „Reîncarcă pagina”, apoi dă câteva click-uri cât timp bara main.js nu e plină. Cu replay activ, contoarele „prind din urmă” după hidratare; dezactivează-l și repetă: click-urile se pierd.
Feedback vizual în fereastra de hidratare

Replay-ul salvează acțiunea, dar butonul nu reacționează vizual până la hidratare. Stările CSS (:hover, :active, :focus-visible) funcționează fără JS — folosește-le, ca utilizatorul să știe că click-ul „a prins”.

Hidratare incrementală cu @defer

Un @defer obișnuit randează pe server doar @placeholder-ul: trigger-ele nu rulează pe server. Un trigger hydrate schimbă asta: serverul încarcă dependențele blocului și randează conținutul principal. În browser, blocul rămâne deshidratat — HTML-ul se vede, dar chunk-ul JS al componentelor din el nici măcar nu e descărcat — până când se declanșează trigger-ul. Atunci Angular descarcă chunk-ul, hidratează blocul și reia evenimentele din coadă.

Două consecințe practice. Prima: poți pune @defer și deasupra fold-ului fără layout shift, pentru că pe ecran e deja conținutul final, nu placeholder-ul. A doua: un eveniment pe un element cu listener dintr-un bloc deshidratat îi declanșează hidratarea, oricare ar fi trigger-ul declarat — click-ul nu se pierde. Excepție face hydrate never: subarborele lui nu e deloc adnotat, deci nu are ce relua.

<app-header />                                    <!-- fără @defer: hidratat la bootstrap -->

@defer (hydrate on interaction) {
  <app-gallery [images]="product().images" />     <!-- JS-ul galeriei: abia la primul click -->
} @placeholder {
  <div class="gallery-skeleton"></div>            <!-- folosit doar la navigare client-side -->
}

@defer (hydrate on hover) {
  <app-recommendations [productId]="id()" />
} @placeholder {
  <div class="reco-skeleton"></div>
}

@defer (hydrate on idle) {
  <app-support-chat />
} @placeholder {
  <button>Chat</button>
}

@defer (hydrate on viewport) {
  <app-reviews [productId]="id()" />              <!-- sub fold: JS când intră în ecran -->
} @placeholder {
  <div class="reviews-skeleton"></div>
}

@defer (hydrate never) {
  <app-footer />                                  <!-- HTML static pentru totdeauna -->
}
LiveInsule hidratate la cerere (simulare)
JS descărcat: 0 KB din 218 KB · 0/6 blocuri vii
Headerfără @defer (main.js)deshidratat48 KB, nedescărcat
Galeriehydrate on interactiondeshidratat36 KB, nedescărcat
imaginea 1 / 4
Recomandărihydrate on hoverdeshidratat22 KB, nedescărcat
Husă Aria · 49 lei
Chat suporthydrate on idledeshidratat30 KB, nedescărcat
Ai întrebări?
Descrierea produsului, specificații, livrare…
↓ derulează până la recenzii ↓
Recenziihydrate on viewportdeshidratat64 KB, nedescărcat
★★★★☆ · 3 recenzii afișate
Footerhydrate neverstatic, fără JS0 KB (ar fi 18)
Contact · Termeni · Retur · © 2026
  • Simularea pornește când demo-ul intră în ecran (sau apasă „Reîncarcă”).
Click pe galerie, treci cu mouse-ul peste recomandări, derulează până la recenzii. Urmărește ce bloc se hidratează, de ce și câți KB costă; apoi comută pe „Completă” și compară JS-ul descărcat la pornire.

Trigger-ele de hidratare

@defer (hydrate on idle) { … }                    <!-- requestIdleCallback -->
@defer (hydrate on idle(500)) { … }               <!-- idle, dar cel târziu după 500 ms -->
@defer (hydrate on viewport) { … }                <!-- conținutul blocului intră în ecran -->
@defer (hydrate on viewport({ rootMargin: '200px' })) { … }  <!-- doar opțiuni literale -->
@defer (hydrate on interaction) { … }             <!-- click / keydown în bloc -->
@defer (hydrate on hover) { … }                   <!-- mouseover / focusin în bloc -->
@defer (hydrate on immediate) { … }               <!-- imediat după restul paginii -->
@defer (hydrate on timer(2s)) { … }               <!-- ms sau s -->
@defer (hydrate when cartReady()) { … }           <!-- condiție din componenta părinte -->
@defer (hydrate never) { … }                      <!-- niciodată; fără alte hydrate triggers -->
@defer (hydrate on viewport; hydrate on timer(5s)) { … }  <!-- mai multe = oricare (OR) -->

<!-- ✗ erori de compilare -->
@defer (hydrate on interaction(btn)) { … }        <!-- interaction/hover nu primesc referință -->
@defer (hydrate on viewport({ trigger: el })) { … }
@defer (hydrate never; hydrate on idle) { … }     <!-- never exclude orice alt hydrate trigger -->
TriggerSe declanșeazăParametri
hydrate on idlebrowserul e liber (requestIdleCallback)opțional, un timeout: idle(500)
hydrate on viewportconținutul blocului intră în ecranopțional, opțiuni IntersectionObserver literale; fără referință la alt element
hydrate on interactionclick sau keydown în blocniciunul
hydrate on hovermouseover sau focusin în blocniciunul
hydrate on immediateimediat ce restul paginii a terminat de randat—
hydrate on timer(…)după un intervalobligatoriu, în ms sau s
hydrate when exprexpresia devine truthyfuncționează doar pe blocul deshidratat cel mai de sus
hydrate neverniciodată: HTML static, cu tot subarborelenu se combină cu alte trigger-e hydrate

Mai multe trigger-e pe același bloc se combină cu „oricare” (OR). hydrate when are o limită: expresia aparține componentei părinte, care trebuie să fie ea însăși hidratată ca expresia să poată fi evaluată.

Blocuri imbricate

Arborele de componente e ierarhic: un copil nu poate fi activ fără părintele lui. Dacă trigger-ul se declanșează pe un bloc imbricat, Angular hidratează lanțul de sus în jos — întâi blocul deshidratat cel mai de sus, apoi pe rând până la cel care a cerut.

@defer (hydrate on interaction) {
  <app-product-tabs />                <!-- 1. se hidratează întâi părintele… -->
  @defer (hydrate on hover) {
    <app-size-guide />                <!-- 2. …apoi copilul, chiar dacă hover-ul a fost pe el -->
  }
}

Hydrate triggers în CSR și la navigare

Hidratarea e o optimizare a încărcării inițiale de conținut randat pe server. Când utilizatorul ajunge la aceeași pagină prin navigare client-side (un routerLink), sau când aplicația nu are SSR deloc, trigger-ele hydrate sunt ignorate: blocul se comportă ca un @defer obișnuit, cu @placeholder și trigger-ele normale. Dacă nu ai pus niciun trigger normal, compilatorul adaugă on idle.

@defer (on interaction; hydrate on viewport) {
  <app-reviews />
} @placeholder {
  <button>Arată recenziile</button>
}

<!--
  Încărcarea inițială, pagină randată pe server:
    → serverul randează <app-reviews /> (nu placeholder-ul)
    → în browser rămâne HTML static până intră în viewport (hydrate on viewport)

  Navigare client-side (routerLink) sau aplicație fără SSR:
    → hydrate on viewport e ignorat
    → se vede @placeholder, blocul se încarcă la click (on interaction)
    → fără trigger normal, implicit ar fi fost on idle
-->
  • @placeholder rămâne necesar — nu apare la încărcarea inițială cu SSR, dar apare la orice navigare client-side spre pagină.
  • hydrate never înseamnă „niciodată JS la încărcarea inițială”. La o randare client-side ulterioară, blocul își descarcă totuși dependențele, cu trigger-ul normal.
  • Într-o aplicație fără provideClientHydration() (sau cu withNoIncrementalHydration()), blocurile cu trigger-e hydrate produc în dev mode avertismentul NG0508.

Erori de nepotrivire

Hidratarea pornește de la o promisiune: DOM-ul din browser e exact cel produs de server, inclusiv comentariile și spațiile. Orice lucru care încalcă promisiunea — parser-ul HTML al browserului, un script terț, un CDN, o ramură de template diferită — se termină într-una din trei situații: eroare, avertisment sau, cel mai perfid, nicio eroare dar o re-randare vizibilă.

CodÎnseamnăCauza tipică
NG0500nodul găsit nu e cel așteptat (alt tag sau tip) ori lipseșteHTML invalid, manipulare directă a DOM-ului, script terț
NG0501lipsesc noduri fratenoduri șterse din afara Angular
NG0502nu găsește nodul la poziția așteptatăstructură modificată după server
NG0503noduri proiectate create în afara AngularcreateComponent cu projectableNodes din DOM nativ
NG0504ngSkipHydration pe un element care nu e gazdă de componentăatributul pus pe un div
NG0505(avertisment) lipsesc adnotările de pe serverprovideClientHydration() lipsește din config-ul de server
NG0506(avertisment) aplicația nu devine stabilă în 10 sPendingTasks nefinalizate; cu Zone.js, timere în zona Angular
NG0507HTML-ul a fost modificat după serverCDN care elimină comentariile
LiveExplorator de nepotriviri (simulare)
Codul tău
<p class="promo">
  <div>Livrare gratuită azi</div>
</p>
HTML trimis de server
<p class="promo"><div>Livrare gratuită azi</div></p>
DOM în browser, înainte de hidratare
<p class="promo"></p><div>Livrare gratuită azi</div><p></p>
eroare · NG0500
Consola
NG0500: During hydration Angular expected <div> but the node was not found.

Angular expected this DOM:

  <p class="promo">
    <div>…</div>  <-- AT THIS LOCATION
    …
  </p>

To fix this problem:
  * check the "PromoBanner" component for hydration-related issues
  * check to see if your template has valid HTML structure
  …

Ce se întâmplă: Serverul construiește DOM-ul prin API-uri, deci nesting-ul invalid supraviețuiește până la serializare. Parser-ul HTML din browser închide însă <p> când întâlnește <div>, iar Angular nu mai găsește nodul așteptat.

Fix: HTML valid: <p> acceptă doar conținut inline. Folosește un <div class="promo"> ca părinte sau un <span> în interior.

Alege un pattern: vezi codul, HTML-ul trimis de server, DOM-ul pe care îl găsește Angular în browser și rezultatul. Mesajele de consolă sunt preluate (prescurtat) din sursele Angular 22.
Ramuri diferite pe server și în browser

@if (isPlatformBrowser(…)) în template nu aruncă eroare, dar e una dintre cele mai scumpe greșeli: Angular aruncă DOM-ul serverului pentru bloc și îl reface, cu layout shift. Ține output-ul identic pe ambele platforme și mută inițializarea de browser în afterNextRender — sau folosește @defer, care randează pe server placeholder-ul. Variantele sunt pe pagina Cod compatibil cu serverul.

ngSkipHydration: ieșirea de urgență

Pentru o componentă care nu poate fi reparată imediat (tipic: o librărie care desenează direct în DOM, ca D3), atributul ngSkipHydration pe gazda ei o scoate din hidratare: componenta și copiii ei sunt distruși și re-randați, exact ca fără hidratare. Funcționează doar pe gazde de componente (altfel NG0504), iar pus pe componenta rădăcină dezactivează hidratarea pentru toată aplicația.

<!-- pe gazda componentei care manipulează DOM-ul direct (ex. un grafic D3) -->
<app-sales-chart ngSkipHydration [data]="sales()" />

<!-- ✗ NG0504: doar pe gazde de componente, nu pe elemente obișnuite -->
<div ngSkipHydration><app-sales-chart [data]="sales()" /></div>

Debugging

  • Consola, în dev mode: după ce aplicația devine stabilă apare un rezumat. Dacă nu-l vezi, hidratarea nu a pornit (verifică NG0505).
  • Angular DevTools arată starea de hidratare a fiecărei componente și poate activa un overlay peste părțile hidratate; la o eroare de nepotrivire, evidențiază componenta vinovată.
  • View source vs Elements: View source e HTML-ul de pe server, Elements e DOM-ul curent. Diferențele dintre ele (un tbody apărut, un banner inserat) sunt exact cauzele de NG0500.
  • Dezactivează JavaScript-ul în DevTools și reîncarcă: vezi exact ce primește utilizatorul înainte de hidratare.
  • NG0506: provideStabilityDebugging() listează task-urile care țin aplicația instabilă (cu Zone.js, importă și zone.js/plugins/task-tracking).
  • preserveWhitespaces trebuie să aibă aceeași valoare în tsconfig.app.json și tsconfig.server.json; implicitul (false) e varianta recomandată.
Angular hydrated 14 component(s) and 212 node(s), 0 component(s) were skipped.
5 defer block(s) were configured to use incremental hydration.
Learn more at https://angular.dev/guide/hydration.

Când DA, când NU

Folosește
  • Hidratare: oricând ai SSR sau prerender. Fără ea, SSR-ul își pierde jumătate din sens (DOM-ul e refăcut).
  • Event replay: implicit; contează mai ales pe pagini cu acțiuni rapide (coș, like, meniu) și rețele lente.
  • hydrate on viewport pentru tot ce e sub fold: recenzii, produse similare, footer bogat.
  • hydrate on interaction / hover pentru widget-uri grele care stau degeaba până la prima atingere: galerii, filtre, selectoare de mărime.
  • hydrate never pentru conținut cu adevărat static: articol, termeni, footer fără logică.
Evită / alternativa
  • Aplicații fără SSR: trigger-ele hydrate nu fac nimic. Folosește @defer cu trigger-e normale.
  • @defer (hydrate …) pe componente de câțiva KB: chunk-ul în plus și request-ul costă mai mult decât economisești.
  • hydrate never pe ceva care are listeneri sau stare: nu vor funcționa niciodată la încărcarea inițială.
  • ngSkipHydration ca „fix” permanent: repară cauza (HTML valid, afterNextRender, DOM manipulat prin Angular).
  • Ramuri isPlatformBrowser în template pentru a ascunde problemele: alternativa e @defer sau afterNextRender.

Capcane frecvente

Manipulare directă a DOM-ului

nativeElement.appendChild, innerHTML, document.querySelector(…).remove() în componente care rulează și pe server produc structuri pe care hidratarea nu le poate potrivi. Folosește template-ul (@if, @for, binding-uri, Renderer2) și amână codul strict de browser în afterNextRender.

  • HTML invalid: <div> în <p>, <a> în <a>, tabel fără <tbody>. Validează template-ul; browserul „repară” HTML-ul altfel decât l-a scris serverul.
  • Valori diferite pe server și în client (Date.now(), Math.random(), ID-uri generate, fus orar): fără eroare, dar textul se schimbă sub ochii utilizatorului. Transferă valoarea cu TransferState.
  • Scripturi terțe (analytics, consent, chat) care modifică DOM-ul înainte de hidratare: încarcă-le după, cu afterNextRender.
  • withEventReplay() și withIncrementalHydration() lăsate „pentru siguranță” în v22: primul e redundant, al doilea e deprecated. provideClientHydration() simplu ajunge.
  • @placeholder șters pe blocurile cu hydrate, „că oricum nu se vede”: la navigarea client-side se vede.
  • Date personale în transfer cache: răspunsurile ajung în HTML. Request-urile cu Authorization/Cookie sunt excluse implicit — nu le include cu includeRequestsWithAuthHeaders fără motiv; folosește filter sau transferCache: false.
  • CDN cu minificare HTML care șterge comentariile → NG0507 pe toate paginile.

Fișă rapidă

// ── Config (app.config.ts; ajunge și pe server prin mergeApplicationConfig)
provideClientHydration();                                     // v22: DOM + transfer cache + incremental + replay
provideClientHydration(withNoIncrementalHydration(), withEventReplay());
provideClientHydration(withI18nSupport());
provideClientHydration(withHttpTransferCacheOptions({ filter, includeHeaders, includePostRequests }));
provideClientHydration(withNoHttpTransferCache());
http.get(url, { transferCache: false });                      // opt-out per request

// ── Template
// @defer (hydrate on idle | idle(ms) | viewport | viewport({ rootMargin }) | interaction | hover | immediate | timer(2s))
// @defer (hydrate when cond)      @defer (hydrate never)      @defer (on idle; hydrate on viewport)
// <app-chart ngSkipHydration />   host: { ngSkipHydration: 'true' }   ← ultimă soluție

// ── Erori
// NG0500 nod diferit   NG0501 lipsesc frați   NG0502 lipsește nodul   NG0503 noduri proiectate din afara Angular
// NG0504 ngSkipHydration pe non-componentă    NG0505 lipsesc adnotările (provider lipsă pe server)
// NG0506 aplicația nu devine stabilă în 10 s  NG0507 HTML modificat după server (comentarii șterse)
// NG0508 hydrate triggers fără hidratare incrementală activă

Cap. 12 · 0 din 3 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. SSR, prerender & render modes
  2. Hidratare: event replay & incremental
  3. Cod compatibil cu serverul
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