Angular's latest versions have introduced powerful features that many developers haven't explored yet — signals, deferred loading, SSR with hydration, and the new control flow syntax.
Signals — Fine-Grained Reactivity
import { Component, signal, computed, effect } from "@angular/core"
@Component({
selector: "app-counter",
template: `
<p>Count: {{ count() }}</p>
<p>Doubled: {{ doubled() }}</p>
<button (click)="increment()">+1</button>
`
})
export class CounterComponent {
count = signal(0)
doubled = computed(() => this.count() * 2)
constructor() {
effect(() => {
console.log(`Count changed: ${this.count()}`)
})
}
increment() {
this.count.update(c => c + 1)
}
}
New Control Flow
@Component({
template: `
@if (user()) {
<h1>Welcome, {{ user().name }}</h1>
@for (item of items(); track item.id) {
<div class="item">{{ item.name }} - {{ item.price | currency }}</div>
} @empty {
<p>No items found</p>
}
} @else {
<app-login />
}
@switch (status()) {
@case ("loading") { <app-spinner /> }
@case ("error") { <app-error [message]="error()" /> }
@case ("success") { <app-dashboard [data]="data()" /> }
}
`
})
HttpClient — Type-Safe HTTP
import { HttpClient } from "@angular/common/http"
import { inject } from "@angular/core"
interface User { id: number; name: string; email: string }
export class UserService {
private http = inject(HttpClient)
getUsers() {
return this.http.get<User[]>("/api/users")
}
createUser(user: Partial<User>) {
return this.http.post<User>("/api/users", user)
}
updateUser(id: number, data: Partial<User>) {
return this.http.patch<User>(`/api/users/${id}`, data)
}
deleteUser(id: number) {
return this.http.delete(`/api/users/${id}`)
}
}
Deferred Loading
Lazy-load components based on triggers:
@Component({
template: `
<h1>Dashboard</h1>
@defer (on viewport) {
<app-analytics-chart />
} @placeholder {
<div class="skeleton">Loading chart...</div>
} @loading (minimum 500ms) {
<app-spinner />
}
@defer (on interaction) {
<app-comments [postId]="postId" />
} @placeholder {
<button>Load Comments</button>
}
@defer (on timer(3s)) {
<app-recommendations />
}
`
})
SSR with Hydration
// app.config.ts
import { provideClientHydration, withEventReplay } from "@angular/platform-browser"
export const appConfig = {
providers: [
provideClientHydration(withEventReplay())
]
}
Resource & rxResource (Angular 19+)
import { resource, signal } from "@angular/core"
@Component({
template: `
@if (userResource.isLoading()) {
<app-spinner />
} @else if (userResource.error()) {
<p>Error: {{ userResource.error() }}</p>
} @else {
<h1>{{ userResource.value().name }}</h1>
}
`
})
export class UserComponent {
userId = signal("1")
userResource = resource({
request: this.userId,
loader: async ({ request: id }) => {
const res = await fetch(`/api/users/${id}`)
return res.json()
}
})
}
Key Takeaways
- Signals for fine-grained reactivity without RxJS
- New control flow (@if, @for, @switch) replaces *ngIf/*ngFor
- Deferred loading (@defer) for lazy component loading
- SSR hydration with event replay
- resource() for declarative async data fetching
- Standalone components — no NgModules needed
Explore Angular docs for the complete API.
Building web scrapers or data pipelines? Check out my Apify actors for ready-made solutions, or email spinov001@gmail.com for custom development.
Top comments (0)