Angular 21 - Variable change not rendered in DOM

3 weeks ago 26
ARTICLE AD BOX

When the variables are not updating as expected in Angular 21.

We can immediately assume the problem might be zoneless change detection.

The solution when using zoneless, is to use signals for each property in the component. The value changes on the signals will trigger change detection on the particular DOM and view is refreshed.

Change detection fires only when necessary, so we get a performance boost.

Converting the components to signals:

Home Page TS:

export class HomePage { loading = signal<boolean>(false); @ViewChild(WaitingScreenComponent) waitingScreen!: WaitingScreenComponent; constructor() { this.displayWaitingScreen(); } displayWaitingScreen() { this.loading.set(true); of(true) .pipe(delay(2000)) .subscribe(() => { console.log('Simulate Countdown Launch'); this.waitingScreen.startCountdown(); }); } handleCountdownFinished() { this.loading.set(false); } }

Home Page HTML:

<ion-header [translucent]="true"> <ion-toolbar> <ion-title>Home Page</ion-title> </ion-toolbar> </ion-header> <ion-content fullscreen="false"> @if(loading()){ <app-waiting-screen (onCountdownFinished)="handleCountdownFinished()"> </app-waiting-screen> }@else{ <ion-card (click)="displayWaitingScreen()"> <ion-card-content> <div>Display Waiting Screen</div> </ion-card-content> </ion-card> } </ion-content>

Waiting Screen HTML:

<div class="loading-overlay"> <div class="song-info-card"> <h2>Title</h2> <h4>artist</h4> <ion-spinner name="bubbles"></ion-spinner> @let countdownVal = countdown(); @if (countdownVal !== null) { <div class="countdown">{{ countdownVal }}</div> }@else{ <p class="loading-message">Loading music ...</p> } </div> </div>

Waiting Screen TS:

export class WaitingScreenComponent { countdown = signal<number | null>(null); onCountdownFinished = output(); constructor() {} startCountdown() { this.countdown.set(3); console.log(this.countdown); const interval = setInterval(() => { this.countdown.update((prev: number | null) => (prev || 0) - 1); console.log(this.countdown); if (this.countdown() === 0) { clearInterval(interval); setTimeout(() => { this.onCountdownFinished.emit(); console.log('Finished'); }, 500); } }, 1000); } }

Stackblitz Demo


If you do not want to use zoneless. Then add the below two items and Angular will work as usual using zone based change detection.

import 'zone.js'; import { bootstrapApplication } from '@angular/platform-browser'; ... bootstrapApplication(AppComponent, { providers: [ ... provideZoneChangeDetection({ eventCoalescing: true }), ], });

Stackblitz Demo

Read Entire Article