AngularAtlased. 22.2

Cap. 14Reactivitate avansată61 / 75

Semnalele pe dinăuntru

Graful reactiv: producători și consumatori, push-pull, de ce computed e lazy și glitch-free, problema diamantului și când rulează efectele.

arhitectură ~0 min de citit Documentația oficială

Pe pagina signal() și computed() ai văzut ce fac semnalele. Pagina asta arată cum funcționează pe dinăuntru: un graf reactiv construit automat din citiri, în care scrierile împing doar o notificare, iar recalcularea are loc abia când cineva citește. De aici vin toate proprietățile utile: computed e leneș și memorat, nu vezi niciodată stări intermediare inconsistente, iar Angular poate re-randa doar componentele afectate, fără Zone.js.

De ce contează
Odată ce înțelegi modelul, intuiești singur multe lucruri: de ce un computed scump nu costă nimic dacă nu e citit, de ce items().push() nu actualizează UI-ul, de ce un effect care setează alt semnal e o idee proastă, sau de ce un semnal citit într-o ramură if uneori „nu reacționează”.

Producători, consumatori și graful

Fiecare semnal e un nod în graf. signal() e un producător. computed() e și consumator (citește alte semnale), și producător (alții îl citesc pe el). effect() și template-urile componentelor sunt consumatori. În timpul rulării unei funcții reactive există un consumator activ, iar orice semnal citit în acel moment devine dependența lui. Graful nu se declară: se construiește din citiri.

Fiecare nod are o version care crește doar când produce o valoare diferită de cea anterioară. Unii consumatori sunt „live” (effect-urile și template-urile); pentru ei, graful ține și muchii inverse, de la producător la consumator, ca să le poată trimite notificări. Tipurile primitive din @angular/core/primitives/signals arată exact aceste câmpuri: version, dirty, producers, consumers.

const a = signal(1);                                  // producător
const b = signal(2);                                  // producător
const sum = computed(() => a() + b());                // consumator ȘI producător
const product = computed(() => a() * b());
const result = computed(() => sum() + product());     // diamant: a și b ajung aici pe două drumuri

// În timpul rulării unei funcții reactive, Angular ține un „consumator activ”.
// Orice semnal citit acum devine dependența lui. Nu declari nimic: graful se construiește din citiri.

Push, apoi pull

O scriere (set/update) nu recalculează nimic. Doar crește versiunea semnalului și anunță consumatorii live că ar putea fi murdari: aceasta e faza push. Când consumatorul rulează din nou (template-ul la următoarea randare, effect-ul la rândul lui), citește ce are nevoie, iar fiecare computed își verifică producătorii: s-a schimbat vreo versiune? Doar atunci se recalculează. Aceasta e faza pull.

a.set(5)
  │  PUSH: a își crește `version` și anunță consumatorii „live” (template, effect) că POT fi murdari.
  │        Nimic nu se recalculează încă.
  ▼
template / effect marcat dirty  →  change detection programează o randare
  │
  ▼
template citește result()
  │  PULL: result își verifică producătorii (sum, product) — au altă versiune?
  │        sum își verifică producătorii (a, b) — a are altă versiune → sum se recalculează.
  │        Dacă valoarea nouă e EGALĂ cu cea veche, versiunea lui sum nu crește → propagarea se oprește.
  ▼
result se recalculează o singură dată, cu valori deja consistente (glitch-free)

Consecința importantă: un computed se recalculează abia după ce toate scrierile s-au terminat, cu valori deja consistente. În diamantul din demo, result nu vede niciodată sum nou cu product vechi. Asta se numește glitch-free. Iar dacă modifici a și b în același click, result se recalculează o singură dată.

LiveGraful reactiv, instrumentat (semnale reale)
a = 1signalb = 2signal sum = calculat × product = calculat × result = calculat × template consumator

În template: a = 1, b = 2 · result = 5

Ce a „văzut” result la fiecare recalculare:
    Apasă „a + 1”: sum, product și result se recalculează câte o dată. Apasă butonul care le schimbă pe amândouă: tot o singură recalculare. Debifează „template-ul citește result” și schimbă a: nimic nu se mai calculează (lazy). Jurnalul arată că result vede mereu perechi consistente.

    Lene și memorare

    Documentația Angular o spune direct: un computed e evaluat leneș și memorat. Funcția nu rulează până la prima citire. Apoi valoarea e păstrată și refolosită până când o dependență se schimbă. Practic, poți pune derivări scumpe (filtrare, sortare) în computed: costă doar când chiar e nevoie de rezultat.

    const expensive = computed(() => {
      console.log('calculez…');
      return items().filter(matches).sort(byPrice);
    });
    
    items.set(newItems);  // nu se afișează nimic: nimeni n-a citit încă
    expensive();          // „calculez…” — prima citire
    expensive();          // nimic: valoare memorată (memoized)
    items.set(other);     // tot nimic — marcat ca vechi, nu recalculat
    expensive();          // „calculez…”

    Egalitate: unde se oprește propagarea

    Versiunea unui nod crește doar dacă valoarea nouă nu e „egală” cu cea veche. Implicit egalitatea e Object.is: pentru obiecte și array-uri contează referința, nu conținutul. Același mecanism se aplică și unui computed. Dacă rezultatul lui nu se schimbă, consumatorii lui nu se mai recalculează, chiar dacă dependențele lui s-au schimbat. Cu { equal } definești tu ce înseamnă „la fel”.

    // Implicit: Object.is. Pentru obiecte/array-uri contează REFERINȚA.
    const tags = signal(['a', 'b']);
    tags.set(['a', 'b']);           // altă referință → valoare „nouă” → consumatorii se recalculează
    
    // Egalitate custom: valoarea nu se schimbă dacă e „la fel” după regula ta
    const sameItems = (x: string[], y: string[]) => x.length === y.length && x.every((v, i) => v === y[i]);
    const stableTags = signal(['a', 'b'], { equal: sameItems });
    stableTags.set(['a', 'b']);     // egal → versiunea nu crește → nimic downstream
    
    // Și un computed are egalitate: dacă rezultatul e egal, propagarea se oprește la el
    const parity = computed(() => (n() % 2 ? 'impar' : 'par'));   // n: 0 → 2 → 4 … parity rămâne 'par'
    LiveEquality cutoff, cu contoare
    n = 0 · Numărul e par
    NodValoareRecalculări
    parity = computed(() => n() % 2 ? 'impar' : 'par')
    label = computed(() => 'Numărul e ' + parity())
    Semnalcount = computed(tags().length)
    signal(...) — egalitate implicită (Object.is) 2 · recalculat ×
    signal(..., { equal: sameItems }) 2 · recalculat ×
    Apasă „n + 2” de câteva ori: parity se recalculează (n s-a schimbat), dar rămâne „par”, deci label NU se mai recalculează. Apoi setează același array: cu egalitatea implicită, count se recalculează; cu equal custom, nu.

    Dependențe dinamice

    La fiecare rulare, lista de producători a unui consumator se reconstruiește din ce a citit efectiv. Un semnal citit doar într-o ramură if e dependență doar cât timp acea ramură se execută. E un câștig de performanță, dar și o sursă de confuzie: „schimb details și nu se întâmplă nimic” e de obicei corect, pentru că ramura curentă nu-l citește.

    const view = computed(() => {
      if (showDetails()) {
        return details();     // dependențe: showDetails + details
      }
      return summary();       // dependențe: showDetails + summary
    });
    // La fiecare rulare, lista de producători se reconstruiește din ce s-a citit EFECTIV.
    // Cât timp showDetails() e false, schimbarea lui details nu recalculează view.
    LiveCe citește un computed, la fiecare rulare

    view() = rezumat v0

    Dependențe înregistrate la ultima rulare: · view recalculat ×

    Cu showDetails = false, apasă „schimbă details”: view nu se recalculează, pentru că nu depinde de details. Comută showDetails și repetă: acum details e dependență, iar summary nu mai e.

    Effect-uri și template-uri: consumatorii live

    Effect-urile rulează asincron, în timpul procesului de change detection, nu în momentul set(). Documentația v22 distinge două feluri. Un view effect e creat în contextul unei componente: rulează înainte ca acea componentă să fie verificată și e distrus odată cu ea. Un root effect e creat într-un serviciu din root: rulează înainte de verificarea tuturor componentelor și trăiește cât aplicația. Dacă o dependență se schimbă chiar în timpul execuției, effect-ul mai rulează o dată înainte să continue change detection.

    // View effect: creat în contextul unei componente → rulează ÎNAINTE ca acea componentă
    // să fie verificată de change detection; e distrus odată cu componenta.
    @Component({ /* ... */ })
    export class Profile {
      constructor() {
        effect(() => console.log('profil', this.user()));
      }
    }
    
    // Root effect: creat într-un serviciu din root → rulează înaintea verificării tuturor componentelor;
    // trăiește cât aplicația.
    @Injectable({ providedIn: 'root' })
    export class Analytics {
      constructor() {
        effect(() => track(this.route()));
      }
    }
    // Ambele sunt asincrone (nu rulează în momentul set()), legate de procesul de change detection.

    Template-ul unei componente e și el un consumator reactiv. Când un semnal citit în template se schimbă, Angular marchează componenta pentru verificare (ca markForCheck), iar change detection o re-randează doar pe ea și strămoșii ei. Pe asta se sprijină aplicațiile zoneless și OnPush implicit din v22 (vezi Change detection).

    @Component({
      template: `<p>{{ fullName() }}</p>`,   // template-ul e un consumator reactiv
    })
    export class Card {
      readonly first = signal('Ana');
      readonly fullName = computed(() => `${this.first()} Pop`);
    }
    // first.set('Ioana') → nodul reactiv al template-ului e marcat dirty → componenta e marcată pentru
    // verificare (ca markForCheck) → change detection o re-randează. Fără Zone.js, fără verificarea
    // întregului arbore: așa funcționează aplicațiile zoneless.

    Când DA, când NU

    Folosește modelul în avantajul tău
    • Derivări scumpe în computed: se calculează doar la nevoie și o singură dată per schimbare.
    • Lanțuri de computed-uri în loc de un singur computed uriaș. Cu equality cutoff, schimbările mici se opresc devreme.
    • { equal } pentru valori recreate des, dar „la fel” (filtre, liste de id-uri de la server).
    • untracked pentru citiri care nu trebuie să declanșeze nimic (logging, analytics).
    Lucruri pe care graful nu le face pentru tine
    • Nu detectează mutații: push pe un array dintr-un semnal nu anunță pe nimeni.
    • Nu îți ordonează efectele secundare: dacă ai nevoie de ordine strictă în timp, folosește RxJS (vezi RxJS avansat).
    • Nu e un mecanism de evenimente: „s-a dat click” nu e stare. Folosește output() sau un Subject.
    • Nu rulează effect-urile sincron: dacă ai nevoie de rezultat imediat, derivă cu computed.

    Capcane frecvente

    // ✗ Scriere într-un computed — eroare: „Writing to signals is not allowed in a `computed`”
    const total = computed(() => {
      count.set(items().length);       // efect secundar în derivare
      return items().reduce(sum, 0);
    });
    
    // ✗ Effect folosit pentru derivare (o randare în plus, risc de bucle)
    effect(() => total.set(items().reduce(sum, 0)));
    
    // ✓ Derivarea e un computed
    const total2 = computed(() => items().reduce(sum, 0));
    
    // ✗ Mutare: aceeași referință → Object.is spune „egal” → nimic nu se actualizează
    items().push(newItem);
    // ✓
    items.update((list) => [...list, newItem]);
    • „Nu reacționează”: verifică dacă semnalul e citit pe ramura care rulează și dacă îl citești cu (). O referință la semnal fără apel nu creează dependență.
    • Obiecte mari într-un singur semnal: orice câmp schimbat recalculează tot ce depinde de obiect. Împarte starea sau derivă câmpurile cu computed.
    • Effect care scrie în alte semnale: randări în plus și risc de bucle. Aproape mereu e un computed sau un linkedSignal.
    • Citiri în constructor „ca să fie gata”: un computed citit prea devreme se calculează cu date incomplete. Lasă-l leneș.

    Fișă rapidă

    NOD           ROL                     CÂND RULEAZĂ
    signal        producător              — (doar își schimbă valoarea și versiunea la set/update)
    computed      consumator + producător lazy: la citire, doar dacă vreo dependență s-a schimbat
    effect        consumator „live”       asincron, în change detection (view: înaintea componentei; root: înaintea tuturor)
    template      consumator „live”       când componenta e re-randată după ce a fost marcată dirty
    
    REGULI
      dependențele = ce citești EFECTIV la ultima rulare (dinamice, pe ramuri)
      egalitate implicită Object.is; { equal } pentru valori „la fel” → oprește propagarea
      computed fără cititori nu se calculează deloc
      nu scrie semnale în computed; nu deriva stare cu effect
      untracked(() => …) citește fără să creeze dependență

    Cap. 14 · 0 din 4 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. Semnalele pe dinăuntru
    2. RxJS avansat: operatori de ordin superior
    3. NgRx SignalStore
    4. Mașini de stări cu signals
    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