1 of 61

Il nuovo volto di Angular�Più semplice 🎯�Più veloce ⚡️�Più potente 🚀

2 of 61

BEGINNER

EXPERT

INTERMEDIATE

3 of 61

Davide Passafaro

davide-passafaro

davidepassafaro

Angular Google Developer Expert

GDG Roma Città Organizer

Angular Roma Organizer

Senior Frontend Engineer @

4 of 61

AngularJS - 2010

  • Template dichiarativi
  • Two-way binding
  • Direttive

5 of 61

Angular 2 - 2016

  • Typescript
  • Zone.js
  • RxJs

ebbasta

Z

6 of 61

I punti deboli di Angular

🧠 Complessità e curva di apprendimento ripida

🐢 Prestazioni in app complesse

🔒 Limitata flessibilità rispetto a librerie più leggere

🧩 Verbosità del codice

📉 SEO limitato nelle SPA

🔄 Aggiornamenti frequenti e breaking changes

7 of 61

Angular 3 - 2023

  • Nuovo logo
  • Nuova documentazione
  • Nuova filosofia

naaah

8 of 61

Standalone Components

9 of 61

AppComponent

10 of 61

@NgModule({

declarations: [

HeaderComponent,

FooterComponent,

HighlightDirective,

TruncatePipe

],

imports: [ CommonModule, FormsModule, ReactiveFormsModule ],

exports: [

HeaderComponent,

FooterComponent,

HighlightDirective,

TruncatePipe

],

providers: [ LoggerService ]

})

export class SharedModule {}

11 of 61

<section class="dashboard" appSectionHighlight>

<h1 appTitleCase>Panoramica Utente</h1>

<div *appShowWhenReady="isDataLoaded">

<p>Benvenuto, {{ userName | appFormatName }}</p>

<ul>

<li

*ngFor="let item of items"

[appSelectableItem]="item === selectedItem"

>

{{ item.label }}

</li>

</ul>

</div>

</section>

12 of 61

@NgModule({

// Il nostro unico componente

declarations: [ItemComponent],

// Moduli base di cui ha bisogno

imports: [CommonModule, ...],

// Lo rendiamo disponibile ad altri moduli

exports: [ItemComponent]

})

export class ItemModule {}

13 of 61

componente + modulo = standalone

@Module

@Component

14 of 61

@Component({

selector: 'app-page',

standalone: true,

imports: [NgIf, TitleCasePipe, CardComponent],

providers: [MyService],

template: `

<h1>{{ title | titlecase }}</h1>

<p *ngIf="showCard">

<app-card></app-card>

</p>

`

})

export class PageComponent {

title = 'ciao a tutti';

showCard = true;

constructor(private service: MyService) {

service.log('PageComponent inizializzato');

}

}

Default con v19

15 of 61

@Component({

selector: 'app-admin-page',

standalone: true,

imports: [DashboardComponent]

})

export class AdminPageComponent {}

export const routes: Routes = [

{ path: 'dashboard', component: DashboardComponent }

];

Come modulo

Come componente

16 of 61

platformBrowserDynamic().bootstrapModule(AppModule)

.catch(err => console.error(err));

const routes: Routes = [

{ path: '', component: HomeComponent },

{ path: 'about', component: AboutComponent }

];

@NgModule({

declarations: [

AppComponent,

HomeComponent,

AboutComponent

],

imports: [

BrowserModule,

RouterModule.forRoot(routes)

],

bootstrap: [AppComponent]

})

export class AppModule {}

bootstrapApplication(AppComponent, appConfig)

.catch(err => console.error(err));

const routes = [

{ path: '', component: HomeComponent },

{ path: 'about', component: AboutComponent }

];

const appConfig = {

providers: [provideRouter(routes)]

};

AppComponent

AppModule

17 of 61

📦

🪦

📚

I moduli ancora sono supportati, ma per casi avanzati

Librerie

Feature design

Compatibilità con codice legacy

18 of 61

I principali vantaggi

  • I componenti sono ora vere entità singole
  • La manutenzione dei componenti è ora molto più facile
  • Chi impara oggi Angular deve imparare un concetto in meno
  • Alcune feature come il @defer funzionano solo con gli standalone

19 of 61

Il nuovo control flow

e le nuove istruzioni

20 of 61

<div *ngIf="users.length > 0; else noUsers">

<ul>

<li

*ngFor="let user of users"

[ngClass]="{ 'active-user': user.active }"

[ngStyle]="{ 'font-weight': user.active ? 'bold' : 'normal' }"

>

{{ user.name }} <span *ngIf="user.active">(Attivo)</span>

</li>

</ul>

</div>

<ng-template #noUsers>

<p>Nessun utente disponibile.</p>

</ng-template>

21 of 61

22 of 61

<div *ngIf="isLoggedIn; else loggedOut">

<p>Welcome back, {{ username }}!</p>

</div>

<ng-template #loggedOut>

<p>Please log in.</p>

</ng-template>

@if (isLoggedIn) {

<p>Welcome back, {{ username }}!</p>

} @else if (isGuest) {

<p>Hello Guest, please sign up!</p>

} @else {

<p>Please log in.</p>

}

*ngIf

@if

23 of 61

<ul>

<li *ngFor="let user of users; let i = index; trackBy: trackById">

{{ i + 1 }}. {{ user.name }}

</li>

<li *ngIf="products.length === 0" class="empty">No users found</li>

</ul>

<ul>

@for (user of users; track user.id; let i = $index) {

<li>{{ i + 1 }}. {{ user.name }}</li>

} @empty {

<li>No users found</li>

}

</ul>

*ngFor

@for

24 of 61

<div [ngSwitch]="role">

<p *ngSwitchCase="'admin'">

Admin

</p>

<p *ngSwitchCase="'user'">

User

</p>

<p *ngSwitchDefault>

Guest

</p>

</div>

@switch (role) {

@case ('admin') {

<p>Admin</p>

}

@case ('user') {

<p>User</p>

}

@default {

<p>Guest</p>

}

}

[ngSwitch]

@switch

25 of 61

@Component({

selector: 'app-example',

standalone: true,

imports: [

CommonModule,

NgIf,

NgFor,

NgSwitch,

NgSwitchCase,

NgSwitchDefault

],

template: `...`

})

export class ExampleComponent {}

26 of 61

Migrazione automatica con le schematics

27 of 61

I principali vantaggi

  • Leggere i template e molto più facile
  • Non serve importare alcun modulo
  • Non ci servono elementi wrapper come <ng-container>
  • Performance migliori (fino al 90% nel caso di @for)
  • Bundle size più piccolo
  • @switch ha il type checking, che [ngSwitch] non aveva
  • Migrazione facilissima grazie alle schematics di Angelo

28 of 61

<div [ngClass]="{ admin: isAdmin, dense: density === 'high' }"></div>

<div [ngStyle]="{ color: isActive ? 'green' : 'red', 'font-size.px': fontSize }"></div>

<div [class]="{ admin: isAdmin, dense: density === 'high' }"></div>

<div [style]="{ color: isActive ? 'green' : 'red', 'font-size.px': fontSize }"></div>

[ngClass] e [ngStyle]

[class] e [style]

ng generate @angular/core:ngclass-to-class

ng generate @angular/core:ngstyle-to-style

29 of 61

@Component({

selector: 'app-example',

standalone: true,

imports: [

CommonModule,

NgIf,

NgFor,

NgSwitch,

NgSwitchCase,

NgSwitchDefault,

NgClass,

NgStyle

],

template: `...`

})

export class ExampleComponent {}

30 of 61

I principali vantaggi

  • Non serve importare alcun modulo
  • Migliori performance
  • Bundle size più piccolo
  • Migrazione facilissima grazie alle schematics di Angelo

31 of 61

Signals, Signal-based APIs e Angular Zoneless

32 of 61

@Component({

selector: "my-component",

template: `

<div>{{ counter }}</div>

<button (click)="increase()"></button>

`,

})

export class MyComponent {

counter = 0;

increase(): void {

this.counter++;

}

}

@Component({

selector: "my-component",

template: `

<div>{{ counter }}</div>

<button (click)="increase()"></button>

`,

})

export class MyComponent {

counter = 0;

increase(): void {

setInterval(() => {

this.counter++;

}, 1000);

}

}

Zone.js

Z

Grazie a

33 of 61

NgZone

AppComponent

ApplicationRef

ApplicationRef

AppComponent

Event

34 of 61

<main>

<h2>Hello {{ firstName }}!</h2>

<input type="text" [(ngModel)]="firstName" />

</main>

<img

[alt]="hero.name"

[src]="hero.imageUrl"

/>

<app-hero-detail

[hero]="hero"

/>

@if(show){

@for (item of list; track item.id) {

<p>{{ item.name }}</p>

<img [src]="item.image" />

}

}

35 of 61

@Component({

selector: 'my-card',

templateUrl: './my-card.component.html',

changeDetection: ChangeDetectionStrategy.OnPush

})

export class MyCardComponent {

...

}

36 of 61

@Component({

selector: 'my-component',

template: `

<button (click)="addItem()">Add</button>

<my-child [items]="items" />

`

})

export class MyComponent {

items = [];

addItem() {

this.items.push(42);

this.items = [...this.items, 42];

}

}

@Component({

selector: 'my-component',

template: `

<button (click)="loadData()">Load</button>

<my-child [items]="items" />

`

})

export class MyComponent {

cdr = inject(ChangeDetectorRef);

myService = inject(MyService);

items = [];

loadData() {

this.myService.getData().subscribe(data => {

this.items = data;

this.cdr.markForCheck();

})

}

}

37 of 61

Default

OnPush

Controlla tutti i valori associati ai componenti�ad ogni evento

Scatena la CD in caso di

  • input aggiornati
  • eventi interni
  • markForCheck( )

Performance

DevEx

38 of 61

// Signal

const year = signal(2025);

const confName = signal('DevFest Modena');

year.set(2026);

year.update(year => year + 1);

// Computed

const message = computed(() => `${confName()} ${year()}`);

// Effect

effect(() => {

console.log(`Ciao ${message()}`);

});

39 of 61

// Signal

const year = signal(2025);

const confName = signal('DevFest Modena');

year.set(2026);

year.update(year => year + 1);

// Computed

const message = computed(() => `${confName()} ${year()}`);

// Effect

effect(() => {

console.log(`Ciao ${message()}`);

});

40 of 61

// Signal

const year = signal(2025);

const confName = signal('DevFest Modena');

year.set(2026);

year.update(year => year + 1);

// Computed

const message = computed(() => `${confName()} ${year()}`);

// Effect

effect(() => {

console.log(`Ciao ${message()}`);

});

41 of 61

@Component({

selector: 'app-example',

template: `

<p>Benvenuti al {{ message() }}</p>

<button (click)="incrementYear()"> +1 </button>

`,

})

export class ExampleComponent {

year = signal(2025);

confName = signal('DevFest Modena');

message = computed(() => `${this.confName()} ${this.year()}`);

constructor() {

effect(() => console.log(`Ciao ${this.message()}`));

}

incrementYear() {

this.year.update(y => y + 1);

}

}

42 of 61

I principali vantaggi

  • Angular può tenere traccia di dove sono utilizzati
  • Ci permettono di derivare dati da altri Signal in modo reattivo
  • Sono altamente ottimizzati per l'uso nei template:
    • Contengono necessariamente un valore
    • Non propagano la notifica in caso di nuovo valore identico al corrente
    • computed ed effect tracciano solo i signal da cui sono realmente dipendenti
    • Il valore derivato dei computed è memoizzato e non viene ricalcolato

43 of 61

Signal-based APIs

  • input( ) e output( )
  • model( )
  • viewChild( ) e viewChildren( )
  • contentChild( ) e contentChildren( )

44 of 61

@Component({

selector: 'app-counter',

template: `

<h3>Contatore: {{ count }}</h3>

<button (click)="decrement()">-</button>

<button (click)="increment()">+</button>

`

})

export class CounterComponent {

@Input() count = 0;

@Output() countChange = new EventEmitter<number>();

increment() {

this.countChange.emit(this.count + 1);

}

decrement() {

this.countChange.emit(this.count - 1);

}

}

@Component({

selector: 'app-counter',

template: `

<h3>Contatore: {{ count }}</h3>

<button (click)="decrement()">-</button>

<button (click)="increment()">+</button>

`

})

export class CounterComponent {

count = input<number>();

countChange = output<number>();

increment() {

this.countChange.emit(this.count() + 1);

}

decrement() {

this.countChange.emit(this.count() - 1);

}

}

input( ) e output( )

@Input e @Output

45 of 61

@Component({

selector: 'my-component',

template: `

<h2>{{ firstName }}</h2>

<p>Age: {{ age }}</p>

<p *ngIf="isAdult">✅ Adult</p>

<p *ngIf="!isAdult">❌ Minor</p>

`

})

export class MyComponent implements OnChanges {

@Input() firstName: string = '';

@Input() age: number = 0;

isAdult: boolean = false;

ngOnChanges(): void {

this.isAdult = this.age >= 18;

}

}

@Component({

selector: 'my-component',

template: `

<h2>{{ firstName() }}</h2>

<p>Age: {{ age() }}</p>

<p *ngIf="isAdult()">✅ Adult</p>

<p *ngIf="!isAdult()">❌ Minor</p>

`

})

export class MyComponent {

firstName = input<string>('');

age = input<number>(0);

isAdult = computed(() => this.age() >= 18);

}

computed( ) e effect( )

ngOnChanges( )

46 of 61

@Component({

selector: 'app-counter',

template: `

<h3>Contatore: {{ count }}</h3>

<button (click)="decrement()">-</button>

<button (click)="increment()">+</button>

`

})

export class CounterComponent {

@Input() count = 0;

@Output() countChange = new EventEmitter<number>();

increment() {

this.countChange.emit(this.count + 1);

}

decrement() {

this.countChange.emit(this.count - 1);

}

}

@Component({

selector: 'app-counter',

template: `

<h3>Contatore: {{ count }}</h3>

<button (click)="decrement()">-</button>

<button (click)="increment()">+</button>

`

})

export class CounterComponent {

count = model<number>();

increment() {

this.count.set(this.count() + 1);

}

decrement() {

this.count.set(this.count() - 1);

}

}

model( )

@Input e @Output

47 of 61

@ViewChild('input') input!: ElementRef;

@ViewChildren(ItemComponent) items!: QueryList<ItemComponent>;

@ContentChild('input') input!: ElementRef;

@ContentChildren(ItemComponent) items!: QueryList<ItemComponent>;

input = viewChild<ElementRef>('input');

items = viewChildren(ItemComponent);

input = contentChild<ElementRef>('input');

items = contentChildren(ItemComponent);

@ViewChild e @ViewChildren, @ContentChild e @ContentChildren

viewChild( ) e viewChildren( ), contentChild( ) e contentChildren( )

48 of 61

I principali vantaggi

  • Niente più boilerplate ngOnChanges con input o model
  • Meno boilerplate in caso di two-way binding con model
  • Ottimizzare la change detection è molto più semplice
  • I risultati delle query sono più puntuali e sensati
  • TypeScript riesce a dedurre meglio i tipi delle queries
  • Migrazione automatica con ng generate @angular/core:signals

49 of 61

BUT

Zone.js

Z

50 of 61

Zone on, Zone off

51 of 61

Zoneless è finalmente stabile 🥳

ng new app��? Do you want to create a 'zoneless' application without zone.js? (y/N)

bootstrapApplication(AppComponent, {

providers: [provideZonelessChangeDetection()]

});

npm uninstall zone.js

52 of 61

WRAP UP

53 of 61

Angular continua ad evolvere da 15 anni

AngularJS�2010

Angular�2016

Angular�2023

54 of 61

Signals e�Zoneless

Standalone Components

Cosa abbiamo visto oggi

Nuovo�Control Flow

55 of 61

Il nuovo Angular ha anche tanto altro

  • inject function
  • Resource API
  • SSR e Hybrid rendering
  • Signal forms
  • Directive composition API
  • Hot module replacement
  • linkedSignal
  • Deferrable views
  • esbuild & Vite
  • Selectorless components
  • Istruzioni enter/leave
  • @let nei template

56 of 61

I punti deboli di Angular

🧠 Complessità e curva di apprendimento ripida

🐢 Prestazioni in app complesse

🔒 Limitata flessibilità rispetto a librerie più leggere

🧩 Verbosità del codice

📉 SEO limitato nelle SPA

🔄 Aggiornamenti frequenti e breaking changes

Talk a parte

57 of 61

Z

58 of 61

59 of 61

Il nuovo volto di Angular

🎯 Più semplice con gli standalone component

⚡️ Più veloce con le nuove istruzioni

🚀 Più potente grazie ai Signal e a Zoneless

60 of 61

Grazie

61 of 61

Davide Passafaro

davide-passafaro

davidepassafaro

Angular Google Developer Expert

GDG Roma Città Organizer

Angular Roma Organizer

Senior Frontend Engineer @