16

I created a NativeScript app with angular 2, i have an array of objects that i expect to see in the frontend of the application. the behaviour is that if i push an object into the array directly inside the ngOnInit() it works, but if i create a promise in the ngOnInit() it doesn't work. here is the code:

export class DashboardComponent {
     stories: Story[] = [];

     pushArray() {
         let story:Story = new Story(1,1,"ASD", "pushed");
         this.stories.push(story);
     }

     ngOnInit() {
         this.pushArray(); //this is shown

         var promise = new Promise((resolve)=>{
             resolve(42);
             console.log("promise hit");
         });

         promise.then(x=> {
             this.pushArray(); //this is NOT shown
         });
     }
 }

the relative html is:

<Label *ngFor="let story of stories" [text]='story.message'></Label>

when the app starts i see only one push, but than i created a button that trigger a "console.log(JSON.stringify(this.stories));" and at that moment, when i tap the button, the ui seems to detects the changed array, and the other pushed object appears.

EDIT:

I created a more simple example in this thread: Angular 2: when i change a variable in a promise.than in ngOnInit the view doesn't refresh

Community
  • 1
  • 1
Andrea Veronesi
  • 201
  • 1
  • 3
  • 8

3 Answers3

25

The change detection is based on references, and pushing an element to an array will not trigger it. Try updating the reference like this:

this.stories.push(story);
this.stories = this.stories.slice();
nickspoon
  • 1,347
  • 12
  • 18
  • @nickspoon what does slice exatcly – tero17 Sep 22 '17 at 23:45
  • 2
    @Zammel It creates a copy of part of the array, but used like this with no arguments it just makes a shallow copy of the entire array: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice – nickspoon Sep 24 '17 at 07:16
  • it does not work for me. i want to remove children view because of the children view has input and output decorator from the list. – Sulaiman Triarjo Feb 16 '19 at 10:37
0
        setTimeout(function () {
            this.stories.push(story);
        }, 0);

I had reall trouble with pushing into nested array, with almost random refresh results, till i stumped on this spec :

Basically application state change can be caused by three things:

  • Events - click, submit, …

  • XHR - Fetching data from a remote server

  • Timers - setTimeout(), setInterval()

(https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html#what-causes-change)

So I tried setTimeout, and miraculously it worked ...

Jiro Matchonson
  • 875
  • 1
  • 17
  • 24
0

I think the best way to solve this problem is add in the *ngFor directive (trackBy:trackByFn):

<Label *ngFor="let story of stories; trackBy:trackByFn" [text]='story.message'></Label>

and in Typescript add the trackByFn method in the class component:

trackByFn(index: any, item: any) {
    return index;
}
Dmitry S.
  • 1,544
  • 2
  • 13
  • 22