Paul Cosma
Paul Cosma

Reputation: 313

Angular array change detection issue

I am working on a notification component in which I have an array of "error" objects and iterate through them using *ngFor. My issue is that Angular won't pick up the changes to the array when I mutate it inside a subscription.

My code is the following:

  ngOnInit() {
    this.store.select().pipe(
      map(state => state.error),
      filter(error => !!error),
      map(error => ({text: error, display: 'block'}))
    ).subscribe(error => {

      // this does not get detected
      this.errors.push(error);

      setTimeout(() => {
        error.display = 'none';
      }, 4000)
    });

    // this gets detected
    this.errors.push({
      text: 'asd',
      display: 'block'
    })
  }

And the related html:

      <div class="notification-wrapper">
          <div *ngFor="let error of errors" [style.display]="error.display" class="notification is-danger has-text-right">
              {{ error.text }}
          </div>
      </div>

The weird thing is that if I replace the subscription with a setInterval in which I constantly add dummy errors, the changes are caught by Angular and it behaves normally.

Can someone explain to me why it works this way, and maybe how to fix this? Thank you.

Upvotes: 1

Views: 421

Answers (1)

yurzui
yurzui

Reputation: 214047

Looks like your code is executed outside of Angular zone. You can force to run it inside:

import { NgZone } from '@angular/core';

constructor(private ngZone: NgZone) {}

...

this.store.select().pipe(
  map(state => state.error),
  filter(error => !!error),
  map(error => ({text: error, display: 'block'}))
).subscribe(error => {

  this.ngZone.run(() => {
    this.errors.push(error);

    setTimeout(() => {
      error.display = 'none';
    }, 4000)
  });
});

Upvotes: 2

Related Questions