AngularAtlased. 22.2

Cap. 07Arhitectura aplicației41 / 75

Style guide & naming

Convențiile oficiale actuale: nume de fișiere fără sufixe, protected, readonly, ordinea membrilor.

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

Ghidul oficial de stil a fost rescris în 2025 (odată cu v20) și CLI-ul a schimbat convențiile implicite: fișierele nu mai au sufixe de tip (.component.ts, .service.ts), iar clasele nu mai au Component la final. Ideea: numele descrie ce e lucrul, nu ce tip de artefact Angular este.

LiveConvertor de nume
Modern (CLI v20+, style guide actual)Clasic (cu sufixe)
Fișieruser-profile-card.ts / .html / .scssuser-profile-card.component.ts
Clasă / funcțieUserProfileCardUserProfileCardComponent
Selector / numeapp-user-profile-cardapp-user-profile-card
Comandă CLIng generate component user-profile-card # ng g c …
Scrie un nume și alege tipul: vezi numele de fișier, clasa și selectorul în ambele convenții.

Fișiere

user-profile.ts          ← componenta (clasa UserProfile)
user-profile.html        ← template
user-profile.scss        ← stiluri
user-profile.spec.ts     ← test
                         același nume de bază = ușor de găsit, ușor de mutat împreună

auth-store.ts            ← serviciu cu stare
users-api.ts             ← serviciu de acces la date
time-ago-pipe.ts         ← pipe (clasa TimeAgoPipe)
auth-guard.ts            ← guard funcțional (authGuard)
Nu e obligatoriu să schimbi

Proiectele existente cu sufixe pot rămâne așa. Contează consecvența. Dacă vrei să păstrezi sufixele și pentru fișierele generate nou:

// Preferi sufixele vechi (.component.ts, .service.ts)? Le poți păstra din angular.json:
{
  "schematics": {
    "@schematics/angular:component": { "type": "component" },
    "@schematics/angular:directive": { "type": "directive" },
    "@schematics/angular:service": { "type": "service" },
    "@schematics/angular:guard": { "typeSeparator": "." },
    "@schematics/angular:pipe": { "typeSeparator": "." }
  }
}
// Important e să fie CONSECVENT în tot proiectul.

Ordinea membrilor într-o componentă

@Component({
  selector: 'app-user-profile',
  imports: [Avatar, DatePipe],
  templateUrl: './user-profile.html',
  styleUrl: './user-profile.scss',
  host: { '[class.compact]': 'compact()' },
})
export class UserProfile {
  // 1. API-ul componentei: inputs, models, outputs (readonly)
  readonly userId = input.required<number>();
  readonly compact = input(false, { transform: booleanAttribute });
  readonly edit = output<number>();

  // 2. Queries (readonly)
  private readonly nameInput = viewChild<ElementRef<HTMLInputElement>>('name');

  // 3. Dependențe (private readonly)
  private readonly users = inject(UsersStore);

  // 4. Stare și derivate — protected dacă le folosește doar template-ul
  protected readonly user = computed(() => this.users.byId(this.userId()));
  protected readonly editing = signal(false);

  // 5. Metode — numite după CE FAC, nu după evenimentul care le declanșează
  protected startEditing(): void {
    this.editing.set(true);
  }
}

Reguli scurte

// ✓ inject() în loc de constructor
private readonly http = inject(HttpClient);

// ✓ protected pentru membrii folosiți doar în template (nu fac parte din API-ul public)
protected readonly fullName = computed(() => `${this.first()} ${this.last()}`);

// ✓ readonly pentru tot ce inițializează Angular: input, output, model, viewChild, signal
readonly value = model(0);

// ✓ host: {} în loc de @HostBinding / @HostListener
host: { '[attr.aria-expanded]': 'open()', '(keydown.escape)': 'close()' }

// ✓ [class.x] / [style.x] în loc de ngClass / ngStyle
// ✓ @if / @for / @switch în loc de *ngIf / *ngFor / ngSwitch
// ✓ hook-uri de lifecycle subțiri: apelează metode cu nume clare
ngOnInit() { this.loadInitialFilters(); }

Numele handler-elor

<!-- ✗ numele descrie evenimentul -->
<button (click)="handleClick()">Salvează</button>
<input (keydown.enter)="onKeydown()" />

<!-- ✓ numele descrie acțiunea -->
<button (click)="saveProfile()">Salvează</button>
<input (keydown.enter)="search()" />

Rezumatul ghidului

RegulăDe ce
Un concept per fișierUșor de găsit, de testat, de mutat.
Același nume pentru .ts/.html/.scss/.spec.tsGrupare vizuală, căutare rapidă.
Organizare pe feature, nu pe tipCe se schimbă împreună stă împreună.
Prefix pe selectori (app-, adm-)Fără coliziuni cu elemente native sau din librării.
inject() în loc de constructorLizibil, merge cu moștenire și funcții.
protected pentru membrii de templateSepară API-ul public de detaliile de afișare.
readonly pentru proprietățile AngularPrevine suprascrierea accidentală a unui semnal.
Logică simplă în templateCalculele merg în computed().
Handler-e numite după acțiunesaveProfile() spune ce face; onClick() nu.

Cum grupezi fișierele în foldere e la Structura de foldere; cum denumești tipurile și modelele, la Interfețe & modele.

Selectori și prefixe

Componentele au selectori de element în kebab-case, cu prefixul proiectului (app-user-card). Directivele au selectori de atribut în camelCase, cu același prefix (appTooltip). Pipe-urile au nume în camelCase, fără prefix. Prefixul se setează o dată în angular.json, iar CLI-ul îl folosește la fiecare ng generate. Regulile @angular-eslint/component-selector și directive-selector le verifică în lint.

@Component({ selector: 'app-user-card' })        // element, kebab-case, cu prefix
@Directive({ selector: '[appTooltip]' })         // atribut, camelCase, cu prefix
@Pipe({ name: 'relativeTime' })                  // camelCase, fără prefix

// angular.json → projects.<app>.prefix: "app"

Migrații automate spre stilul modern

Nu trebuie să rescrii de mână un proiect vechi. Angular CLI are migrații care modifică singure codul, fișier cu fișier. Toate există în Angular 22.2:

ng generate @angular/core:standalone            # NgModule → standalone
ng generate @angular/core:control-flow          # *ngIf / *ngFor → @if / @for
ng generate @angular/core:inject                # constructor → inject()
ng generate @angular/core:signal-inputs         # @Input → input()
ng generate @angular/core:outputs               # @Output → output()
ng generate @angular/core:signal-queries        # @ViewChild & co. → viewChild()
ng generate @angular/core:signals               # cele trei de mai sus, într-un singur pas
ng generate @angular/core:service               # @Injectable → @Service (v22)
ng generate @angular/core:route-lazy-loading    # component: → loadComponent
ng generate @angular/core:self-closing-tag      # <app-x></app-x> → <app-x />
ng generate @angular/core:ngclass-to-class      # [ngClass] → [class]
ng generate @angular/core:ngstyle-to-style      # [ngStyle] → [style]
ng generate @angular/core:cleanup-unused-imports # importuri nefolosite din componente

Rulează câte una, pe o ramură curată, și verifică diff-ul și testele după fiecare. Majoritatea acceptă --path, ca să migrezi doar un folder, deci poți merge treptat, feature cu feature.

Capcane frecvente

  • Două stiluri amestecate în același folder (user.component.ts lângă user-card.ts): e mai rău decât oricare dintre ele, aplicat consecvent.
  • O migrare uriașă într-un singur PR: nimeni nu o poate revizui. Mergi pe foldere și ține migrarea separată de schimbările de logică.
  • Nume generice (utils.ts, helpers.ts, common.service.ts) care ajung să adune orice. Un nume trebuie să spună ce face fișierul.

Fișă rapidă

user-card.ts / .html / .css / .spec.ts   un concept per fișier, fără sufix de tip
class UserCard                            fără Component la final
selector: app-user-card   [appTooltip]   prefix pe selectori
inject()  protected  readonly             în componente
saveProfile()  not  onClick()             handler-e numite după acțiune
ng generate @angular/core:<migrare>

Cap. 07 · 0 din 7 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. Structura de foldere
  2. Shared vs feature
  3. Interfețe & modele
  4. State management cu signals
  5. Style guide & naming
  6. Barrels, aliasuri & granițe
  7. Erori: @boundary & ErrorHandler
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