Web dev and more

Aurelia Components: The .ref Binding Command

July 16, 2017

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 the bind 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 :)