Call Method from HTML Only One Time in Angular2

Call method from HTML only one time in Angular2

Just declare a variable, e.g. private imgUrl: string; then in your ngOnInit() or constructor() call this.imgUrl = getImg() and in your HTML <img src="./image/-ex-{{imgUrl}}.png" />

Call a component method from HTML in Angular2

{{callComponentMethodHere(item)}}

but you should avoid that because the method will be called every time change detection runs. It's better to call the method in code (for example in the constructor(), ngOnInit(), or an event handler, assign the result to a property and from the view bind to that property instead.

Calling event handlers is fine of course:

<button (click)="callComponentMethodHere(item)">click me</button>

Why Angular 2+ innerHTML is calling method multiple times in a single statement, How to solve this

You can use pure pipe to only rerun it if inputs to the pipe have changed:

@Pipe({name: 'functionCaller'})
export class FunctionCallerPipe {
transform(func: any, ...args: any[]): any {
return func(...args);
}
}

And use it like that:

<p [innerHTML]="myfunction| functionCaller : name"></p>
import { Component } from '@angular/core';

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

myfunction(name: string){
alert(name);
return '<div>' + name + '</div>';
}
}

function gets called several times

The caculateFunction(data.price) function will be called every time Angular runs change detection for the component (more precisely for the embedded view created by ngFor). This is because updating DOM is part of change detection and Angular needs to call caculateFunction to know what value to use for DOM update. And change detection cycle can run quite often. So if you have 3 items in the list and CD is triggered 3 times initially, you will see that the function is called 9 times.

If you inspect the updateRenderer function, you shoul see something along these lines:

function(_ck,_v) {
var _co = _v.component;
var currVal_0 = _co.calculateFunction(_v.context.$implicit);
_ck(_v,3,0,currVal_0);
}

Read more about how Angular updates DOM in The mechanics of DOM updates in Angular.

Should I worry about that for performance or just let angular2 do
this?

If calculateFunction(data.price) returns the same result for the same price, it's better to calculate these values beforehand for each item and simply renderer them in the template.

<td>{{ data.no }}</td>
<td>{{ data.name }}</td>
<td>{{ data.calculatePrice) }}</t

In this way you will avoid performance decreasing function calls.

Can Calling Simple Methods in Angular Component Templates Cause Performance Issues?

The ultimately answer to the question, is yes - this will cause performance issues. And fortunately, it's actually easy to demonstrate, why, and how you might go about overcoming them.

For the purposes of illustration, I want you to copy a number of those mat-checkboxes, and insert them into your application somewhere.

Then, on the checkboxLabel method, I want you to put a console log at the very first line. Perform any interaction with the page, ideally check and uncheck one of the boxes.

Now, if you check your console, you might expect to see the checkboxLabel console log, appear once for every mat-checkbox. So if you put three in, you'd expect to see it, 3 times.

But if you followed those instructions exactly, you'll actually see the console log, many times depending on exactly what you kept in your test page and the set up of your project. And by many, we mean certainly 9+ times.

How Did This Happen?

Essentially, core to how Angular works, anytime there is a change in the DOM, every element with a method such as this has to be re-evaluated. It doesn't inherently cache the previous value and compare them, so it has to perform the calculation again, and return a result.

So if you had 20 divs with displayName() in them, that's many changes EVERY time there is a change. Which understandably causes a massive performance issue. When you think that most pages have much more than this displayed, you can see how people struggle to keep their applications performant, not because they're bad at coding - but because they might not understand exactly what's making it lag behind the scenes.

How Might You Overcome This?

Pipes.

If we instead convert our method into a pipe which can still utilize this method, we CAN take advantage of this caching method, and make our overall app performant.

Pipes will ONLY return a different result, and will only call their function, IF the input changes.

So for easiness sake: lets set up a dummy ts file, that has the following array.

labelExamples = [
{ row: '1' },
{ row: '1' },
{ row: '3' }
]

And an html file that has the following code:

<ng-container *ngFor="let l of labelExamples">
<div>{{checkboxLabel(l.row)}}</div>
</ng-container>

And finally, let's jump back into our ts file and say our checkboxLabel function looks like this:

  checkboxLabel(row: string) {
switch (row) {
case '1':
console.log("hello");
return 'Row 1 Label';
default:
console.warn("hello from the other side");
return 'Any other row label'
}
}

(You can use this to test exactly what I've described as above.)

Well if you run this, you'll see exactly as I described, many instances of the console log "Hello" and "Hello from the other side".

But, if we change this to a pipe we could convert the above to the following

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'checkboxLabelPipe'
})
export class checkboxLabelPipe implements PipeTransform {
transform(row: string | string): string {
if (row) {
return this.checkboxLabel(row);
}
return row;
}

checkboxLabel(row: string): string {
switch(row) {
case '1':
console.log('Row 1 called');
return 'Row 1 Label';
default:
console.log('Any other row called');
return 'Any other row label'
}
}
}

Remember this is a pipe, and so it will have to be declared in an NgModule that it's used in, or the global NgModule.

If you were to run this instead, keeping the same html file, and the same array of labelExamples, you would see the exact same result as before except if you look in your console logs, you'll see closer to what you would originally expect. 3 console logs.

By understanding exactly when and how calculations are performed in Angular, and when best to use functions or pipes, you can greatly increase the performance of your entire application.

You can read up more on how Pipes go about achieving this, at the Angular Documentation.
Angular Pipes Documentation

Additionally, for even greater performance boosts, you can look into the memo decorator.
The memo-decorator npm can be found here.
which caches already calculated results and saves you even more performance by returning results it has stored instead of even putting them through the process.



Related Topics



Leave a reply



Submit