Best Parts of Aurelia Part 1 – Composing custom elements / templates

In a renewal of a previous set of posts that I did around Durandal.js, I wanted to start a new series on Aurelia, the successor to Durandal.js and Caliburn.Micro.  Aurelia is an awesome collection of libraries that make up an amazing framework that is focused on future specs of the JavaScript language while still supporting a large set of current browsers.

Code

For this quick highlight of the features we will use this repo, which is a basic layout out with multiple columns which contain some widgets –

https://github.com/PWKad/aurelia-layout

It is a basic fork of the Aurelia skeleton-navigation. For any questions please visit the official gitter –

https://gitter.im/Aurelia/Discuss

Composing templates and custom elements

What’s the difference between using the compose element vs a custom elements? In what situations do we use each of them with Aurelia? How does it fit into the web components spec?

Compose:

  1. Can be used to dynamically compose templates (not forced to define the template type)
  2. Can use same view model but different view for each item in an array
  3. You can separate your views and view models into the smallest bits of (re-usable) code needed.

Imagine you want to create between 1 and 3 number of columns that are in charge of their own visibility and data-binding.  Easy.  Using the compose element with a repeat.for binding.

<compose view-model="./column" model.bind="column" repeat.for="column of selectedColumns.columns"></compose>

In this case we are using the compose element to bind to a template where we can provide our own view-model, view, or model. Let’s dissect what we did above –

Set the view-model to ./column to let the compose custom element know that A view-model can be found in this same folder “./” named column.js “column”. The compose custom element will then look for a corresponding view to bind to, and locates in the same folder or by convention if we have one set.

What’s really cool is we could have bound the view-model to a property so if we were iterating over an array of columns in our parent view-model we could have set a different view-model / view pair based on some condition, such as ‘columns/green’ to indicate a column in good standing vs ‘columns/red’ to represent one in bad standing.

We bind the model to the column, which in this context is set to a column we defined in our repeat.for binding.

This means in the parent view-model (such as layout.js) we need to define a property called columns which is an array, such as –


export class Welcome{
	constructor(){
		this.columns = [{ name: 'column1' }, { name: 'column2' }];
	}
}

Custom element:

A custom element is basically a web component. It uses the future spec to create a view-model / view pair that is highly re-usable and componentized.

Now we need to create a column view template in the same folder. Let’s create a new .html file and wrap the .html in a template tag that let’s Aurelia know this is a template that we want to re-use.



  <div class="column">${column.name} if you lower-case it is ${column.lcName}.</div>


Next we create a view-model to pair up to it to allow handling any of this particular columns’ properties or methods. In this example we create an ES6 module but in our skeleton-navigation app Aurelia can convert this to your favorite module format (AMD, CommonJs, etc…)


export class Column {
  constructor () {
    this.column = { name: '', lcName: '' };
  }

  activate(col) {
    this.column.name = col.name;
    this.column.lcName = col.name.toLowerCase();
  }
}

Here we are defining an activate callback that the module loader will call when first activating the view-model and pass the column we bound the model to before in the parent. This was the compose binding before where we used model.bind in our view.

How does it work together?

In the case above the view model column.js and view column.html make up a custom element. We used the compose custom element to instantiate an instance of it to dynamically render it in the DOM.

What else could we do instead?

We could import it directly in the DOM –

  <import from='./column'></import>

And then use it as a custom element there directly –

<column model.bind="column"></column>

The difference here is we are forced to use the column view-model and view pair.

Wrap-up

What we went over –

1. Compose’ing custom elements allow a very dynamic way to create partials that truly separate out our code in to functional areas.

2. Custom elements are web components that need to be imported or composed to use.

3. The templating engine for Aurelia is truly amazing and built for the future, but designed for use now.

Advertisements