Demystify .call binding

There seems to be few misunderstanding in related to:

something.call="method()"

I want to help to clarify in this post.

  • When you do something.bind="a + 1", the expression a + 1 is evaluated when the binding happens.
  • When you do something.call="method()", the expression method() is NOT evaluated when the binding happens, the method() will be called when later you call something() in JS code (or click.trigger or click.delegate in html).

Most users have picked up the above. But to fully understand it, you have to know the .call doesn’t need to bind to a form of function call like method(), it can bind to any expression, it just delays the evaluation of the expression.

For a concrete example, consider this:
app.html

<template>
  <require from="./play"></require>
  <play on-press.call="count = count + value"></play>
  <p>Count: ${count}</p>
</template>

app.js

export class App {
  count = 0;
}

Two take away:

  1. on-press.call="count = count + value" binds to an expression with side effect.
  2. value is not available in the binding context at the moment.

Aurelia .call give you this nice feature to supply additional binding context when calling the bound procedure, you can do onPress({ value: 1 }) to provide number 1 to property value when calling onPress.

This behaviour is the same one that supports on-press.call="method(value)" and onPress({ value: 1 }). You just need to know there is no special treatment on the syntax method(value).

  1. method(value) is just an expression to be delayed, same as count = count + value.
  2. value is only evaluated when you call onPress(...), which you can supply additional binding context.

Full demo here:

12 Likes

Awesome post :+1: :+1:

1 Like

Thank you very much @huochunpeng.
I´ll memoize .call as ‘lazy bind’ from now on.
:slight_smile:

2 Likes

What are the benefits as compared to just emitting an event?

Yes, event aggregator can be used to cover this communication too. I would say ea can cover more use cases because of total decoupling.

The .call binding does save you from ea.subscribe and subscriber.dispose boilerplate. If an event is going to be consumed by only one subscriber, .call is a cheaper solution. Also .call binding limits the subscriber to be the parent element.

I was thinking about DOM events instead

Events have the notion of bubbling whereas call bindings are directly related to the parent. One way to think about call is to pass in business handlers into a dumb presentational component. So think of a dahsboard where each widget gets an update callback passed and can handle proper timing by itself. With EA the parent would have to orchestrate things

It wouldn’t bubble it not told so, would it?

Thats true, but I was just mentioning it as a benefit for If you need that functionallity. Think of listening on the element vs document like Trigger/Delegate