Aurelia Components: The .ref Binding Command
The .ref
binding is a quite undervalued feature that can help you with several problems in a clean and nice way. Using .ref can reduce the complexity of your application, save bundle size and performance. I want to show you some examples and how to use it.
What is .ref
Since summer 2015 the .ref
binding can be used like all other binding commands (one-way, two-way, one-time, call, ...
). You can use it to create a reference to an HTML element in the DOM, a view model, a view instance or a controller.
The pattern to use it looks the following: <some-element some-attribute.ref="expression">
. There are several possibilities for some-attribute
. You can use view-model.ref
, view.ref
, controller.ref
, attribute.ref
, element.ref
and just ref="expression"
which defaults to element.ref
. The expression can be a variable but it could also be
an array element or an object.
These informations are also listed in the official documentation.
Have a look at the examples below to get a better understanding how to leverage the .ref
binding for your application.
Why you should use .ref
Like I already mentioned the .ref
binding command can make the usage of jQuery needless, therefore you can save the size of it.
Next, to that, you can reference a lot of elements, view model, view instances or controller without the need of searching/traversing the DOM, building complicated structures, referencing and connecting logic over the parent controller/view or working with obscure events.
This makes your life far easier and gives you a mighty and performant way of wiring your application together.
When to use .ref
jQuery is a mighty library that can be used for a variety of use cases. The most common use case is probably to select one single element by some selector and manipulating its DOM or properties. So always when you feel the urge to use jQuery you should think about using .ref instead.
In general, you should use bindables and .call whenever possible because this is more straightforward, better readable and understandable.
One situation where you have to use jQuery is when you need to select multiple elements or when you integrate a jQuery plugin. Here you often have to do something like $('some-selector').plugin({...})
and this will not work if the expression on which you call .plugin({...})
is not a jQuery object. But you can use an element reference instead of a selector so it will be converted to a jQuery object $(yourElementRef).plugin({...})
.
Another use case is when you want to use some properties from a plugin you don´t have under control. E.g. a 3rd party datepicker where you want to use parts of the selected date to show it below the datepicker itself, but the datepicker doesn´t offer a way to get these properties.
At what time to use .ref
You can´t access the referenced element before thebind
lifecycle callback is called. In case you want to access the DOM of a referenced element you have to wait until the attached
callback got called because the DOM needs to be constructed first. So you can´t use the reference in the constructor.
How to use .ref
I put some examples on this Gist, you should have a look at them to while reading the next parts.
Reference Element
You can use element.ref
(or just ref
) on every HTMLElement to create a reference to this element. The reference will be of type HTMLElement. Looking at the properties of HTMLElement (Element and Node) we see that we can do a lot of things with it. Finding or selecting a childElement, execute click or blur functions, adding event listeners and much more.
Usage:
//app.html
<div ref="elementRef">
<span> Some text </span>
</div>
//app.js
export class App {
attached() {
console.log(this.elementRef);
}
}
This usage of element.ref
is the most common one. You can use it for referencing specific DOM elements in your own custom component too. We are using it a lot when working with d3.js or HTML Canvas because you can do things like:
//some-chart.js
export class SomeChart {
attached() {
//canvas
let diagramContext = this.diagramCanvasRef.getContext('2d');
//D3
let container = d3.select(this.chartContainerRef);
}
}
Reference View
In difference to element.ref
, view.ref
can only be applied on custom elements and not on normal HTML elements.
Using view.ref
we get access to the Aurelia view instance, having access to several internal properties like the view factory and the bindingContext. The binding context is almost always a view model instance so we can access the view model too.
Usage:
//app.html
<custom-element view.ref="viewRef"></custom-element>
//app.js
export class App {
attached() {
console.log(this.viewRef);
}
}
Have a look at the documentation to understand what you can do with the ViewFactory or see this advanced example from an aurelia core team member on how to use the ViewFactory.
Reference (Attribute) View Model
Referencing the view model of an element or attribute gives us access to the underlying view model (the class .js file). So we can access all properties and methods and even define new ones.
Usage:
//app.html
//element view model
<custom-element view-model.ref="vmRef"></custom-element>
//attribute view model
<div custom-attribute="value: 42" custom-attribute.ref="attributeRef"></custom-element>
//app.js
export class App {
attached() {
console.log(this.attributeRef);
console.log(this.vmRef);
}
}
Reference Controller
The controller owns the view model and the view and composes them together. The controller instance is also responsible for the element´s lifecycle methods and executes them. Therefore referencing the controller gives you access to the view, the view model and the parents view (scope).
Usage:
//app.html
<custom-element controller.ref="ctrlRef"></custom-element>
//app.js
export class App {
attached() {
console.log(this.ctrlRef);
}
}
See the official docs for more explanations about the controller.
Summary
Some of the examples are really made up because I couldn´t think of a short real world example and the focus lays on showing the syntax and how to access the references in your outer view model.
To summarize you should think about using .ref to select and change the look or behavior of an element/attribute when you can´t customize the element/attribute over bindables.
Found some typo, want to give feedback or discuss? Feel free to contact me :)