OnPush is like guards who only check when someone knocks at the gate:
1@Component({
2 selector: 'app-samurai-card',
3 changeDetection: ChangeDetectionStrategy.OnPush,
4 template: \`
5 <div class="card">
6 <h3>{{ samurai().name }}</h3>
7 <p>Clan: {{ samurai().clan }}</p>
8 </div>
9 \`
10})
11export class SamuraiCardComponent {
12 // Component updates ONLY when:
13 // 1. samurai() signal changes reference
14 // 2. An event (click, input) is triggered
15 // 3. Async pipe receives a new value
16 // 4. We manually call cdr.markForCheck()
17
18 samurai = input.required<Samurai>();
19}1<!-- Load when element enters viewport -->
2@defer (on viewport) {
3 <app-heavy-chart [data]="chartData()" />
4} @placeholder {
5 <div class="chart-placeholder">Chart will load when you scroll down...</div>
6} @loading (minimum 500ms) {
7 <app-spinner />
8} @error {
9 <p>Error loading chart</p>
10}
11
12<!-- Load after interaction -->
13@defer (on interaction) {
14 <app-advanced-editor />
15} @placeholder {
16 <button>Click to load editor</button>
17}
18
19<!-- Load after a delay -->
20@defer (on timer(2000)) {
21 <app-recommendations />
22} @placeholder {
23 <p>Loading recommendations...</p>
24}
25
26<!-- Conditional loading -->
27@defer (when isAdmin()) {
28 <app-admin-panel />
29}For long lists:
1import { ScrollingModule, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
2
3@Component({
4 imports: [ScrollingModule],
5 template: \`
6 <cdk-virtual-scroll-viewport itemSize="50" class="viewport">
7 <div *cdkVirtualFor="let samurai of samuraiList()" class="item">
8 {{ samurai.name }}
9 </div>
10 </cdk-virtual-scroll-viewport>
11 \`,
12 styles: [\`
13 .viewport {
14 height: 400px;
15 }
16 .item {
17 height: 50px;
18 }
19 \`]
20})
21export class VirtualListComponent {
22 samuraiList = signal<Samurai[]>([]); // Even 10,000 elements!
23}1import { NgOptimizedImage } from '@angular/common';
2
3@Component({
4 imports: [NgOptimizedImage],
5 template: \`
6 <!-- Automatic lazy loading, srcset, preconnect -->
7 <img
8 ngSrc="/images/samurai.jpg"
9 width="800"
10 height="600"
11 priority
12 placeholder="/images/samurai-placeholder.jpg"
13 >
14
15 <!-- Fill mode for responsive images -->
16 <div class="image-container">
17 <img ngSrc="/images/background.jpg" fill>
18 </div>
19 \`,
20 styles: [\`
21 .image-container {
22 position: relative;
23 width: 100%;
24 height: 300px;
25 }
26 \`]
27})
28export class OptimizedImageComponent {}