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

2

11

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?

Goosander answered 14/10, 2017 at 22:23 Comment(1)
also check this questionHarmonica
H
18

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:

Harmonica answered 15/10, 2017 at 5:44 Comment(3)
For calculated value, it's better to use method call.Header
@MohamedGara, it depends on the type of operations and how often the input values change. Nothing stops you from doing the following way [health]="health + other". Angular advocates for declarative style, this is as declarative as it getsHarmonica
Last link is dead.Exeunt
H
2

In data binding expressions, we can call functions, but they must be side effects free. Here is the official guidelines to write data binding expressions.

Since Angular change detection is based on unidirectional data flow strategy, changing application state in a data binding expression, can cause incoherence between model and view and in the view it self.

In dev mode, after detecting changes and updating view, Angular do a second pass and check if data binding expressions has changed during change detecting phase. If it was the case it throws an error (Expression has changed after it was checked). So, if we call a function that alter the application state in a data binding expression, Angular detect it.

So, functions with side effects, can only be used in a template statement and side effects free functions can be used both in template expressions and template statements.

Header answered 15/10, 2017 at 7:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.