1

I am trying to call a function everytime my ngFor is done loading data from my API.

but the callback is only triggering on first load of the ngFor.

how can I execute the callback everytime my ngFor is changed;

I used this answer: https://stackoverflow.com/a/38214091/6647448

here is what I have so far...

HTML

<button class="btn" (click)="changeDate()"></button>

<div *ngFor="item of items; let last = last">
    <div>{{item}}{{last ? ngForAfterInit() : ''}}</div>
</div>

TS

this.ngForIsFinished = true;

ngForAfterInit() {
    if (this.ngForIsFinished) {
        this.ngForIsFinished = false;
    }
}

changeDate() {
    // this is where i trigger my ngFor to change its content
}

The person who answered said that you just need to set the ngForIsFinished back to true but I am having a hard time where to set it on my code.

Terence
  • 352
  • 1
  • 5
  • 18
  • What exactly is your use case here? What do you hope to achieve by knowing when the `ngFor` is rerendered? – nash11 Oct 03 '19 at 09:37
  • if the ngFor is rerendered the callback function `ngForAfterInit` will be executed – Terence Oct 03 '19 at 09:38
  • show complete `changeDate()` – Adrita Sharma Oct 03 '19 at 09:40
  • @AdritaSharma my changeDate() requests on my API to get data to be displayed – Terence Oct 03 '19 at 09:44
  • @AdritaSharma the `changeDate()` is a function where another request is made on my API and displayed on my ngFor. – Terence Oct 03 '19 at 09:50
  • Have you tried using the method used in the most voted answer in the link you have provided? – nash11 Oct 03 '19 at 10:20
  • @nash11 i tried it but it throws me an error on viewChildren – Terence Oct 03 '19 at 10:22
  • I think you should try that method rather than the "hack" and show the errors you get when you try that method. – nash11 Oct 03 '19 at 10:31
  • @nash11 I tried the method it works well. but the data rendered by my first ngFor is also included on my newly rendered ngFor. I am using .push() – Terence Oct 03 '19 at 10:36
  • I'm not sure I quite follow. How is the data rendered by your first `ngFor` is also included in the newly rendered `ngFor` when all you're trying to do is find out when the `ngFor` is rerendered? – nash11 Oct 03 '19 at 10:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200343/discussion-between-terence-and-nash11). – Terence Oct 03 '19 at 10:45
  • Have you looked at: https://stackoverflow.com/questions/35819264/angular-2-callback-when-ngfor-has-finished – AT82 Oct 04 '19 at 11:47

2 Answers2

0

Try to use ChangeDetectionStrategy.OnPush and last variable of ngFor. Because ChangeDetectionStrategy.Default always checks methods, so fooMethod(...) will be called multiple items:

<div *ngFor = "let title of iterated; let i=index; let last=last">
  {{last ? fooMethod(last) : '' }}  
</div>

yourComponent.ts:

import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent  {
  name = 'Angular 4';

  iteratedData = [
      {"title":"test1","description":"foo","name":"name1"}, 
      {"title":"test2","description":"foo","name":"name2"}, 
      {"title":"test3","description":"foo","name":"name3"}, 
      {"title":"test4","description":"foo","name":"name4"}
  ];

  fooMethod(v) {
    if (v)
      console.log(`This is from the method ${v}`);
  }
}

UPDATE:

After you've loaded data you should call slice method as Angular 2 change detection strategy doesn't check the contents of arrays or object. So try to create a copy of the array after mutation:

this.iteratedData.push(newItem);
this.iteratedData = this.iteratedData.slice();

OR:

constructor(private changeDetectorRef: ChangeDetectorRef)

And you can call a method markForCheck to trigger a changeDetection:

this.iteratedData.push(newItem);
this.changeDetectorRef.markForCheck();
StepUp
  • 36,391
  • 15
  • 88
  • 148
0

Here is the example:

Component:

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

        @Component({
          selector: 'my-app',
          templateUrl: './app.component.html',
          styleUrls: [ './app.component.css' ]
        })
        export class AppComponent  {
          name = 'Angular 5';
          data:any = [];

          ngAfterViewInit(){
            this.changeDate();

          }

          ngForAfterInit(valuue) {
            alert('FOR LOOP COMPLETED : '+ valuue);
           }


           ChangeDate(){
              let i = 0;
              setInterval(()=>{
                this.data=[];
                for(var j=0; j<10; j++){
                 this.data.push("TEST DATA "+ j+" SET AT :  "+i);
               };
               i+=1;
            },7000);
          }
       }

html:

<div *ngFor="let item of data; let last=last;">
{{item}} {{last? ngForAfterInit(item) :''}}
</div>

SetInterval is like your API which will assign data.This is working for me

https://stackblitz.com/edit/pokemon-app-4n2shk

sudhir
  • 1,387
  • 3
  • 25
  • 43