AngularAtlased. 22.2

Cap. 03Signals & reactivitate13 / 75

signal() și computed()

Primitivele reactive: stare scriibilă, stare derivată, egalitate, untracked și reguli de imutabilitate.

stabil ~0 min de citit Documentația oficială

Un signal este o cutie care ține o valoare și anunță automat pe toți cei care au citit-o atunci când se schimbă. Angular ține evidența: când template-ul, un computed() sau un effect() citește count(), devine dependent de el. Când count se schimbă, doar ce depinde de el se actualizează — fără Zone.js, fără verificarea întregului arbore de componente.

De ce contează în 21 & 22

Din v21 aplicațiile noi sunt zoneless, iar din v22 componentele sunt OnPush implicit. Asta înseamnă că semnalele nu mai sunt „o opțiune modernă” — sunt mecanismul principal prin care Angular știe ce să re-randeze. Dacă ții stare în câmpuri simple și le modifici din setTimeout sau din subscribe, UI-ul poate să nu se mai actualizeze.

Cele trei operații de bază

Creezi cu signal(valoareInițială), citești apelând semnalul ca pe o funcție și scrii cu set() sau update(). Starea derivată o faci cu computed().

import { computed, signal, Signal, WritableSignal } from '@angular/core';

const name: WritableSignal<string> = signal('Ana');

name();                        // citire → 'Ana'
name.set('Maria');             // scriere directă
name.update((n) => n.toUpperCase()); // scriere pe baza valorii vechi

const greeting: Signal<string> = computed(() => `Salut, ${name()}!`);
greeting();                    // 'Salut, MARIA!'
// greeting.set(...)           ✗ computed e read-only

const readonlyName: Signal<string> = name.asReadonly(); // expui fără drept de scriere
LiveCounter cu stare derivată
0
  • double() = 0
  • parity() = par
  • computed recalculat de 1 ori (doar când count s-a schimbat)
Observă contorul de recalculări: computed-ul nu rulează la fiecare randare, ci doar când count se schimbă.

Ce trebuie să reții despre computed()

  • Lazy: nu se calculează până nu îl citește cineva.
  • Memoizat: dacă dependențele nu s-au schimbat, întoarce valoarea din cache — oricât de des îl citești.
  • Dependențe dinamice: urmărește doar semnalele citite efectiv la ultima rulare. Într-un cond() ? a() : b(), când cond e true, schimbările lui b sunt ignorate.
  • Pur: fără efecte secundare (fără HTTP, fără set() pe alte semnale, fără DOM).

Regula de aur: stare derivată = computed()

Orice valoare care poate fi calculată din altă stare nu se stochează separat. Totalul unui coș, lista filtrată, „este formularul valid”, „are utilizatorul drept de admin” — toate sunt computed(). O singură sursă de adevăr, zero sincronizare manuală.

interface CartItem {
  id: number;
  name: string;
  price: number;
  qty: number;
}

export class Cart {
  protected readonly items = signal<CartItem[]>([]);
  protected readonly filter = signal('');

  // ✓ Tot ce se poate calcula din altceva = computed()
  protected readonly visible = computed(() =>
    this.items().filter((i) => i.name.toLowerCase().includes(this.filter().toLowerCase())),
  );
  protected readonly subtotal = computed(() =>
    this.items().reduce((sum, i) => sum + i.price * i.qty, 0),
  );
  protected readonly vat = computed(() => Math.round(this.subtotal() * 0.19));
  protected readonly total = computed(() => this.subtotal() + this.vat());
  protected readonly freeShipping = computed(() => this.subtotal() >= 1000);

  protected changeQty(id: number, delta: number): void {
    this.items.update((items) =>
      items.map((i) => (i.id === id ? { ...i, qty: Math.max(0, i.qty + delta) } : i)),
    );
  }
}
LiveCoș de cumpărături: 1 semnal de date + 6 computed
ProdusPrețCantitateTotal
Tastatură mecanică450 lei
1
450 lei
Mouse ergonomic220 lei
0
0 lei
Monitor 27"1300 lei
0
0 lei
Hub USB-C160 lei
2
320 lei
Articole: 3Subtotal: 770 leiTVA 19%: 146 leiTotal: 916 leiMai adaugă 230 lei pt. transport gratuit
Modifici doar items. Lista filtrată, subtotalul, TVA-ul, totalul și transportul gratuit se derivă singure.
Așa (derivat)
// ✓ O singură sursă de adevăr, restul derivat
export class Cart {
  readonly items = signal<CartItem[]>([]);
  readonly total = computed(() => this.items().reduce((s, i) => s + i.price, 0));

  add(item: CartItem) {
    this.items.update((list) => [...list, item]);
  }

  remove(id: number) {
    this.items.update((list) => list.filter((i) => i.id !== id));
  }
}
Nu așa (stocat + sincronizat)
// ✗ Stare derivată STOCATĂ și sincronizată manual
export class Cart {
  items = signal<CartItem[]>([]);
  total = signal(0);

  add(item: CartItem) {
    this.items.update((list) => [...list, item]);
    this.total.set(this.total() + item.price); // ușor de uitat, ușor de desincronizat
  }

  remove(id: number) {
    this.items.update((list) => list.filter((i) => i.id !== id));
    // bug: am uitat să actualizez total
  }
}

// ✗ La fel de rău: un effect care „copiază” o valoare în alt semnal
effect(() => this.total.set(this.items().reduce((s, i) => s + i.price, 0)));

Imutabilitate: de ce push() nu funcționează

Un semnal decide dacă s-a schimbat comparând valoarea veche cu cea nouă prin Object.is, adică după referință. Dacă modifici un array sau un obiect pe loc, referința rămâne aceeași și nimeni nu e notificat. Template-ul se poate re-randa întâmplător (de exemplu pentru că ai dat click în componentă), dar computed()-urile rămân cu valoarea veche. Rezultatul: un UI parțial actualizat — cel mai greu bug de găsit.

LiveMutație vs update imutabil
Lista randată (tags())
tag-1tag-2
count = computed(() => tags().length)
2
Apasă de câteva ori pe push(): lista se re-randează la click, dar computed-ul rămâne în urmă.
const tags = signal(['a', 'b']);

// ✗ Mutație: aceeași referință de array → Angular NU află nimic
tags().push('c');
tags.set(tags()); // tot nu ajută: Object.is(vechi, nou) === true

// ✓ Mereu o referință nouă
tags.update((t) => [...t, 'c']);                    // adăugare
tags.update((t) => t.filter((x) => x !== 'a'));     // ștergere
tags.update((t) => t.map((x) => (x === 'b' ? 'B' : x))); // modificare

const user = signal({ name: 'Ana', address: { city: 'Cluj' } });
// ✗ user().address.city = 'Iași';
// ✓
user.update((u) => ({ ...u, address: { ...u.address, city: 'Iași' } }));

Egalitate custom cu equal

Uneori primești un obiect nou care e „același” din punct de vedere logic (de exemplu de la un API sau dintr-un formular). Cu opțiunea equal eviți notificări și recalculări inutile.

import { signal } from '@angular/core';

interface Filters {
  query: string;
  page: number;
}

// Implicit: egalitate prin Object.is (referință).
// Cu `equal` decizi tu când două valori sunt „la fel” → nu notifică degeaba.
const filters = signal<Filters>(
  { query: '', page: 1 },
  { equal: (a, b) => a.query === b.query && a.page === b.page },
);

filters.set({ query: '', page: 1 }); // obiect nou, dar „egal” → NIMENI nu e notificat

// Merge și pe computed:
const ids = computed(() => users().map((u) => u.id), {
  equal: (a, b) => a.length === b.length && a.every((id, i) => id === b[i]),
});
Liveequal: aceleași filtre, ca obiect nou — cine reîncarcă lista?
{ query: 'angular', page: 1 }
signal(filters)

1încărcări ale listei

  1. încărcarea #1 · pagina 1
signal(filters, { equal })

1încărcări ale listei

  1. încărcarea #1 · pagina 1
Fiecare card are un effect care ține locul unei reîncărcări a listei (cum ar face un httpResource). Cu equal, un obiect nou cu aceleași valori nu notifică pe nimeni.

untracked(): citire fără dependență

Într-un computed sau effect, orice semnal citit devine dependență. Când vrei doar valoarea curentă, fără să re-rulezi la schimbarea ei, folosește untracked().

import { effect, signal, untracked } from '@angular/core';

const user = signal('Ana');
const theme = signal('dark');

effect(() => {
  // Dependență: user — efectul rulează din nou când user se schimbă
  const name = user();

  // Citire FĂRĂ dependență: schimbarea temei NU re-rulează efectul
  const currentTheme = untracked(theme);

  console.log(`[analytics] ${name} a deschis pagina (tema: ${currentTheme})`);
});

// untracked acceptă și o funcție — util când apelezi cod care citește semnale intern
effect(() => {
  const id = selectedId();
  untracked(() => this.logger.log(`Selectat ${id}`)); // logger-ul poate citi orice semnal
});
Liveuntracked(): care effect rulează din nou când se schimbă tema?
usertheme
const t = theme();rulări: 1
  1. Ana a deschis pagina (tema: dark)
const t = untracked(theme);rulări: 1
  1. Ana a deschis pagina (tema: dark)
Ambele efecte notează utilizatorul și tema, ca exemplul de analytics de mai sus. Al doilea citește tema cu untracked(): vede mereu tema curentă, dar schimbarea temei nu îl mai rulează din nou.

Semnale în servicii: scriere privată, citire publică

Pattern-ul de bază pentru orice stare partajată: semnalul scriibil e private, în afară expui asReadonly() și computed()-uri, iar modificările trec prin metode cu nume clare. Detalii complete în pagina State management.

import { Service, computed, signal } from '@angular/core';

@Service()
export class CounterStore {
  // Scrierea e privată: doar store-ul își modifică starea…
  private readonly _count = signal(0);

  // …iar în afară expui doar citire.
  readonly count = this._count.asReadonly();
  readonly isZero = computed(() => this._count() === 0);

  increment(): void {
    this._count.update((c) => c + 1);
  }
}

Când DA, când NU

Folosește signal / computed
  • Starea unei componente (filtre, selecție, toggle-uri, pagina curentă).
  • Starea partajată dintr-un serviciu / store.
  • Orice valoare afișată în template.
  • Valori derivate: totaluri, liste filtrate, flag-uri (computed).
  • Inputurile componentelor (input() e tot un semnal).
Nu e unealta potrivită
  • Fluxuri de evenimente în timp (websocket, drag, tastare cu operatori complecși) — acolo RxJS e mai expresiv. Vezi Signals ↔ RxJS.
  • Date asincrone de la server — folosește resource / httpResource, nu un semnal setat manual din subscribe.
  • Constante care nu se schimbă niciodată — un readonly simplu e suficient.
  • Stare derivată „editabilă” (selecție care se resetează) — folosește linkedSignal.

Capcane frecvente

  • Uiți parantezele: {{ count }} afișează funcția, nu valoarea. Corect: {{ count() }}.
  • Mutezi în loc să înlocuiești: push, splice, obj.x = 1 nu notifică.
  • Efecte secundare în computed: un computed care face HTTP sau setează alt semnal e un bug în așteptare.
  • Async în computed: computed(async () => ...) întoarce un Promise, nu valoarea. Folosește resource().
  • Citești o singură dată: const x = this.count(); în constructor e o fotografie, nu o legătură reactivă.
  • Sincronizezi cu effect: effect(() => b.set(a() * 2)) → folosește computed (sau linkedSignal dacă b trebuie să fie și scriibil).

Fișă rapidă

// CREARE
const a = signal(0);                       // WritableSignal<number>
const b = signal<User | null>(null);       // tip explicit când pornești cu null
const c = computed(() => a() * 2);         // Signal<number>, read-only, lazy, memoizat

// CITIRE
a();                                       // în TS și în template: {{ a() }}

// SCRIERE
a.set(5);
a.update((v) => v + 1);

// EXPUNERE SIGURĂ
readonly value = this._value.asReadonly();

// OPȚIUNI
signal(x, { equal: (p, n) => p.id === n.id, debugName: 'selected' });

// CITIRE FĂRĂ DEPENDENȚĂ
untracked(a);  untracked(() => a() + b());

// VERIFICĂRI
isSignal(x);  isWritableSignal(x);

Cap. 03 · 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. signal() și computed()
  2. effect() — când DA, când NU
  3. linkedSignal() — stare derivată editabilă
  4. resource, rxResource, httpResource
  5. debounced() — semnale cu întârziere
  6. Liste: căutare, filtrare, sortare, paginare
  7. Observables de la zero
  8. Signals ↔ RxJS
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