Angular @for Loop Not Updating When Signal is Truncated
03:50 12 Nov 2025

Background:

I am working on an Angular 20.3.10 application where I use signals for managing the state of a collection of toast messages. I have SSR and Zoneless enabled and have a web worker registered with plans to learn about PWA.

The Problem:

I have a @for loop in my template that iterates over a signal. The signal is updated correctly when I remove an item, and I have verified this using console.log and an effect() statement. However, the @for loop does not remove the corresponding DOM element when the signal is truncated.

I am using the same signal to run CSS animations which I can see are working. I also tried using ChangeDetectorRef and explicitly marking the component for check after the signal is updated, but the issue persists.

Here is some relevant code:

Toast Service

export interface Toast {
  id: number;
  message: string;
}

@Injectable({
  providedIn: 'root',
})
export class ToastService {
  private readonly toastCollection = signal([]);
  private nextToastId = 0;

  getToastCollectionSignal() {
    return this.toastCollection.asReadonly();
  }

  addToast(message: string): void {
    const toast: Toast = { id: this.nextToastId++, message };
    this.toastCollection.update((toasts) => [...toasts, toast]);
  }

  removeToast(id: number): void {
    this.toastCollection.update((toasts) =>
      toasts.filter((toast) => toast.id !== id)
    );
  }
}

Toast Template

@for (toast of this.toasts(); track toast.id) { }

Toast Component

@Component({
  selector: 'app-toast',
  templateUrl: './toast.html',
  styleUrls: ['./toast.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ToastComponent {
  private toastService = inject(ToastService);
  private cdRef = inject(ChangeDetectorRef);

  toasts = computed(() => this.toastService.getToastCollectionSignal()());

  addToast(): void {
    this.toastService.addToast('New Toast Message');
  }

  removeToast(id: number): void {
    this.toastService.removeToast(id);
    this.cdRef.markForCheck(); // Tried this, but it doesn't help
  }
}

I've used a lot of console.log statements to follow the code execution and everything seems fine. I'm inclined to believe the issue lies in my lack of understanding when it comes to Zoneless Angular and change detection. However, the fact that the animations are working as expected must mean that the DOM is being updated since I'm using CSS native animations (at least I think that's how that works).

angular angular-signals angular-ssr angular20 angular-zoneless