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

When i got to api to get data from server in constructor and store it in local variable. I will loop this variable in html to create the table and show the data in the table. But when I call the function on success api and in it I take the same variable used in HTML, the loop function is run first and after that HTML loop. My requirement is to start the HTML loop first and after it ends in a 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);
   }
}

      

+3


source to share


3 answers


<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 solution above will detect the last iteration of the loop ngFor

. setRating

will be called if the latter is index

not null

.

Try this solution and let me know if you need 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
}

      

+2


source


Basically, you can use the "last" operator * ngFor



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

      

+3


source


So, I've seen the answers (including the accepted ones) and while they are definitely noteworthy, I don't think this is the best way to handle your situation. The reasons have already come in the comments to the accepted answer:

  • When angular fails to run in prodMode

    , you get weird behavior due to double-tapped change detection when not executed in prodMode

    . (Initialization and every change (even one click on one of your items) will double your function due to change detection.

  • Even prodMode

    depending on where yours is initialized array

    , the function can be called multiple times. For example, initialize 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 strange ...).

  • Each triggerd event fires change detection

    , which will end up re-evaluating the property last

    and therefore calling your function again. So clicking on one of your elements (even if you haven't even set up a click listener) will trigger again setRating

    .


Because of this, I suggest trying a different approach. Probably the easiest way I've come across is to use another component

.

Something like that:

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

     ngAfterViewInit() {
          this._setRating();
     }

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

      

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

If your data jobHistory

gets updated in the main component, you just clear it (which will destroy MyTableComponent

), push again on new / updated elements in the array, which will re-initialize the component and finally call setRating

.

If setRating

called too early, it may take a little setTimeout(() => { this._setRating(); });

.

Hope I can help.

+2


source







All Articles