5

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.

4
  • What is this.store? A service? Commented Aug 26, 2016 at 11:20
  • It represents the state of my app. "import {Store} from '@ngrx/store';" Commented Aug 26, 2016 at 12:23
  • Can you post your reducer, please? Commented Aug 26, 2016 at 13:04
  • 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? Commented Aug 26, 2016 at 13:16

3 Answers 3

0

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Under what circumstances will the async pipe not work and the zone boilerplate be required? This is a little disturbing.
Under the circumstances where something outside of Angular is pushing stuff in. Angular doesn't know that something has happened. Internal angular classes do zone.run under the hood to trigger the digest (like when you use the Http service). Its frustrating. And I've been through the same battle myself recently with the async pipe.
Thanks for example about how to workaround, but we should use async pipe - it is best practice. I have very similar problem without using NgRx Store and still do not know where is problem.
0

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();
              }
          }

1 Comment

why to mark it as down?????? it's the way to mark up your changes and start digest cycle. try it please. do not use zone. you need to put it by change detector cycle.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.