Angular - Is binding a component method to DOM target property a wrong practice?

Usman picture Usman · Oct 15, 2017 · Viewed 8.1k times · Source

Say, I have a component which is used as following:

 <health-renderer
      [health]="getHealth()"
      [label]="label">
 <health-renderer>

After reading data-binding related parts from https://angular.io/guide/template-syntax, it seem like the way I am setting target component property health is wrong as the template expression used is getHealth() which is a method. And method binding should only be done with events, not properties. In other words, template expression (the thing on right-hand side of =) need to be a template variable, template reference variable or a component/directive/element property.

If [target]="methodCall()" is a wrong way of doing binding, then why is it allowed by Angular? If this is the right way of doing binding then is my understanding given in last paragraph wrong?

Also, how should I then modify my code to reflect the right thing for:

  1. Showing current health which is say, just a progress bar
  2. Automatically call getHealth(): integer which contains business logic for calculating health. 0 will show nothing on progress bar for health. 100 will fill up the progress bar.

Lastly, I noticed getHealth() getting called like 10-20 times for no reason on each mouse move or click. May be binding a method to a target property is not a good practice because of this change-detection behavior of Angular?

Answer

Max Koretskyi picture Max Koretskyi · Oct 15, 2017

It's fine to use a method call as an expression if you know what you're doing. Here is the quote from the docs:

Although it's possible to write quite complex template expressions, you should avoid them.

A property name or method call should be the norm.

As you noticed Angular executes expressions on each change detection run, so your function will be executed quite often:

Angular executes template expressions after every change detection cycle. Change detection cycles are triggered by many asynchronous activities such as promise resolutions, http results, timer events, keypresses and mouse moves.

So it's still better to try to replace a method call with direct property access in the expression. If your function does the following:

getHealth() {
   return this.health;
}

You can put:

[health]="health"

Read more about change detection here: