Aurelia’s robust binding system allows you to not only bind values into your custom attributes and elements, but also the ability to pass in callback functions as well. While your first instinct might be to try using <my-element callback.bind="myFunction"
you will quickly realise that this will not work because of scoping issues.
This is where .call
comes in. Using .call
allows you to pass in callback functions to your bindables, and when they get called, their scope is retained.
Callbacks Without Parameters
Say we have a custom element we have created called my-custom-element
and it has a bindable property called callback
defined inside of the view-model using
@bindable callback = () => {}
Then our custom element callback binding looks like this:
<my-custom-element callback.call="someCallbackFunction()">
Inside of our custom element, when the callback bindable is fired, it will call our callback function and the scope of someCallbackFunction
will be retained (the view-model it is defined in).
When you are not using parameters things are easy enough. You just need to define your callback with the circular function brackets like you would if you’re using click.delegate
or other more event-type bindings.
Callbacks With Parameters
This is where I see developers get caught out quite a bit, passing parameters to callback functions. Using our above function, let’s say that our callback accepts two parameters: user
and item
.
<my-custom-element callback.call="someCallbackFunction(user, item)">
Inside of your custom element, when you call the callback you might try something like this if you didn’t read or understand the documentation correctly:
this.callback(this.selectedUser, this.selectedItem)
Because of how the .call
feature works, this will not work (as you might have possibly already discovered). This is because you need to pass an object to the callback with your parameters matching the names you use in your HTML.
In our case, we are expecting two parameters: one called user
and one called item
to be passed into the callback.
Inside of our custom element, we need to pass them like this:
this.callback({user: this.selectedUser, item: this.selectedItem})
Now, our values get passed correctly and the callback retains its scope.
The parameters as object thing is an absolute gotcha. Confuses the heck out of me every single time I have to do it!