5
votes

I'm using NgRx Store in my app.

Home.html

<list-objects
      [array]="array| async"
      (Edit)="Edit($event)"
      (Delete)="Delete($event)"
 ></list-objects>

Home.ts

export class HomePage {
     public array: Observable<itm[]>;

     constructor(){
          this.array= this.store.select(state => state.array);

          this.array.subscribe((a) => {
             console.log(a); //VALUES OK
          }
      }

      Edit(event){
          this.store.dispatch(this.actions.updateItem(event.item));
      }
  }

When I edit an item of array, async pipe does not update the view but the values in "array" objects are corrects (console.log inside the subscribe shows the updated value). When I click somewhere in the DOM (open modal, click buttons...), view updates with new values.

I log also in the child component "ngOnChanges" and it doesn't fire with new value.

3
What is this.store? A service? - rinukkusu
It represents the state of my app. "import {Store} from '@ngrx/store';" - Mario Rossi
Can you post your reducer, please? - j2L4e
The code in the question does not appear to be complete; how can you use this.store without its being initialised? Could you post more complete/representative code? - cartant

3 Answers

0
votes

Try something like this:

(Note this code isn't tested).

<list-objects
      [array]="array"
      (Edit)="Edit($event)"
      (Delete)="Delete($event)"
 ></list-objects>

export class HomePage {
     public array: itm[];

     constructor( private zone:NgZone ){
        this.store.select(state => state.array).subscribe((a) => {
              this.zone.run(() => {
                   this.array = a;
              });
          }
      }

      Edit(event){
          this.store.dispatch(this.actions.updateItem(event.item));
      }
  }

I've removed the async pipe from the template, and assigned the array directly. By doing this inside this.zone.run the digest cycle will trigger and your template will re-render.

The digest cycle normally only triggers under a number of pre-defined circumstances e.g. Http method callback, UI input. None of which are occurring here, so Angular doesn't know to update.

0
votes

Try:

constructor(private changeDetector: ChangeDetectorRef) {
              this.array= this.store.select(state => state.array);

              this.array.subscribe((a) => {
                 console.log(a); //VALUES OK
                 this.changeDetector.markForCheck();
              }
          }
0
votes

Change detection isn't triggered by ngrx store automatically (and it shouldn't) so you don't see UI updating. There are only several things which trigger change detection automatically: UI input (click, key presses etc...), HTTP response, timers (setTimeout and setInterval).

You can solve your issue in two ways:

  1. Enable changeDetection: ChangeDetectionStrategy.OnPush and then update your array explicitly with subscribe, in that case you will need to call markForCheck():

    import { ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
    
    
    @Component({
        ...,
        changeDetection: ChangeDetectionStrategy.OnPush
    })
    export class HomePage {
        public array: itm[];
        constructor(private ref: ChangeDetectorRef) {
            this.store.select(state => state.array).subscribe(a => {
                this.arr = a;
                this.ref.markForCheck();
            });
        }
    }
    
  2. The second way is to inject ChangeDetectorRef and call detectChanges() in subscribe. But don't do so. And don't use NgZone for it.

ngrx + ChangeDetectionStrategy.OnPush is a good way to improve your change detection performance.