Lakhvir Singh
Lakhvir Singh

Reputation: 672

How to call a function after HTML content refresh in angular2?

When I hit an api to get data from server in constructor and store it in local variable. I loop this variable in html to build table and show data in table. But when I call a function on api success and in it I loop the same variable which is used in HTML, the loop in function will run first and after that HTML loop. My requirement is to run HTML loop first and after its completion loop in function.

HTML CODE

<table>
   <tr *ngFor="let booking of jobHistory>
      <td>{{booking}}</td>
   </tr>
</table>

TYPESCRIPT CODE

jobHistory : any;    
constructor()
{
  this.service.getCustomerJobHistory().subscribe(   res => { this.jobHistory = res},
                                                    err => console.log(err),
                                                    () => this.setRating()
                                              );


}

setRating()
{
   //I want to run this loop after HTML loop completion.
   for(let booking of this.jobHistory)
   {
     console.log(booking);
   }
}

Upvotes: 2

Views: 3416

Answers (3)

Subtain Ishfaq
Subtain Ishfaq

Reputation: 841

<table>
    <tr *ngFor="let booking of jobHistory; let last = last">
        <td>{{booking}}</td>
        <ng-container *ngIf="last">{{setRating()}}</ng-container>
    </tr>
</table>

setRating() {
   //I want to run this loop after HTML loop completion.
   for(let booking of this.jobHistory) {
       console.log(booking);
   }
}

The above solution will detect the last iteration of the ngFor loop. setRating will be called if the last index is not null.

Try this solution and let me know, if you need any help.

Edit: To avoid multiple execution problems,

lastValue:any;
setRating(last:any) {
   if (this.lastValue==last)
return;

   //I want to run this loop after HTML loop completion.
   for(let booking of this.jobHistory) {
       console.log(booking);
   }
   this.lastValue=last
}

Upvotes: 2

malifa
malifa

Reputation: 8165

So i saw the answers (including the accepted one) and while they are definitely worth knowing, i don't think it's the best way to handle your situation. The reasons already came up in the comments to the accepted answer:

  • When angular isn't run in prodMode you will get weird behaviour due to angulars double powered change detection if not run in prodMode. (Initializing and every change (even a single click on one of your elements) will your function twice due to change detection.

  • Even in prodMode depending on where your array is initialized, the function could be called multiple times. For example initializing your array like this:

    export class YourComp { jobHistory: any[] = ['one', 'two', 'three' ]; setRating() { ... } }

    will call the function three times after it's initialized, even in prodMode (which is very weird...).

  • Every triggerd event, will trigger the change detection which will end in reevaluating the last property and therefore call your function again. So clicking on one of your elements (even though you didn't even setup a click listener) will call setRating again.


Because of this, i suggest to try another approach. The probably easiest way i came up with would be to use another component.

Something like this:

export class MyTableComponent {
     @Input() data: any[];

     ngAfterViewInit() {
          this._setRating();
     }

     private _setRating() {
          console.log('set rating...');
     }
}

As its template it should have the same table you posted in your question. In your parent component you would initialize it with something like <my-table [data]="jobHistory" *ngIf="jobHistory"></my-table>

If your jobHistory data will be updated in your main component, you just clear it (which will destruct the MyTableComponent), push your new / updated elements into the array again, which will reinitialize the component and finally call setRating.

If setRating is called too early, a little setTimeout(() => { this._setRating(); }); would do.

Hope i could help.

Upvotes: 2

Dan R.
Dan R.

Reputation: 648

Basically, you could use the 'last' operator of *ngFor

<table>
   <tr *ngFor="let booking of jobHistory; let l=last">
      <td>{{booking}} {{ l ? setRatings() : null}}</td>
   </tr>
</table>

Upvotes: 3

Related Questions