Announcing The Aurelia 2 Book

Buy the Aurelia 2 book here.

With the Aurelia 2 alpha coming very shortly, I have had plans for a while to write another Aurelia book, this time around on Aurelia 2. I learned a lot writing my first book and admittedly, made a few mistakes. The learning experience was invaluable.

With my first book, it came at a time when the Aurelia documentation was subpar. The book served as more of a stand-in for the lack of detailed and concise documentation. With Aurelia 2, extensive documentation work has been undertaken to the point where a book telling you about every little thing makes no sense.

The Aurelia 2 documentation which is updated regularly can be found here if you are wondering where it is located.

This time around, I wanted to write a book that is different from the first, something fun. So, I set out one night to start writing the Aurelia 2 book, not really having a clear goal in mind and after a couple of days, I had one.

The book will touch upon the fundamentals without parroting the documentation too much, it will support TypeScript and you will build an application using Aurelia 2 to get acquainted. The app you will be building is an online cat pictures store, where you can buy pictures of cats.

What You’ll Learn

In the book you’ll learn not only how to develop an Aurelia application, you”ll get to learn how to work with the great new convention-based router, how to structure your app, how to break things up into components, how to leverage new Aurelia 2 features.

On-top of building an application, you will also learn the crucial skill of how to write unit tests with Jest and how to write integration tests using Cypress to test your application. The book aims to go beyond just being solely about Aurelia 2, giving you practical skills.

What You’ll Build

An online store for selling cat pictures. It’ll have a homepage, category page, a detail page, a checkout screen and logged in/logged out functionality as well. An accompanying local server running SQLlite will allow your app to feel real as things are persisted.

The application will touch upon how you can add in authentication, how you can create routes, creating secured sections and other fundamentals that will translate across to actual real world applications.

Introductory minimum price: $4.99

For early adopters who want to support the development of the book, getting updates as the book goes along, you can get it for as low as $4.99. This is the early adopter price because the book is still in its early days of authoring.

Over time as the book becomes more complete, the minimum price will be increased. If you purchase now, you will get access to all future updates for free at the reduced minimum price. Of course, if you are feeling generous, you can opt to pay more than the minimum and every dollar is appreciated, but not expected.

Please be aware that the book structure is still being finalised, chapters added and moved around. There will be typos, mistakes in the code and possibly even things that change in Aurelia 2 itself which get removed or added to the book.

As Aurelia 2 evolves in development, so too, will the book. For the entire life of Aurelia 2, the book will be updated in step to remain an up-to-date resource. You only purchase once and all future updates to the book are free.

Buy the Aurelia 2 book here.

Crash Course: The Bindable Element In Aurelia 2

In Aurelia 2, a new element called bindable has been introduced which is leveraged in HTML only custom elements. If you want a HTML only custom element which has one or more bindable properties, then you use the bindable element to specify them.

The ability to create bindables for HTML only custom elements existed in Aurelia 1, but was limited. The constraint being the bindable keyword had to be specified on the template element.

<template bindable="user">...</template>

In Aurelia 2, this now becomes something much more simple and clean because template is no longer a requirement for HTML only custom elements.

<bindable name="user" />

Besides the semantics changing, you can now also specify the binding mode for the defined variable. This was not possible in Aurelia 1 when creating HTML custom elements.

Now, simply adding a mode property and valid binding mode value, you can change how the binding works just like you can when configuring the binding mode inside of a view-model.

<bindable name="user" mode="one-way" />

Creating HTML Only Custom Elements In Aurelia 2

If you are already familiar with Aurelia and have worked with Aurelia 1, then HTML custom elements are not a new concept to you. If you’re starting out with Aurelia 2, they might be a new concept to you.

How HTML Only Custom Elements Looked In Aurelia 1

We have a custom element called user-info.html which accepts a user object through a bindable property called user and we display their name and email.

<template bindable="user">
  <p>${user.name}</p>
  <p>${user.email}</p>
</template>

How HTML Only Custom Elements Look In Aurelia 2

The constraint of needing a template tag has been removed in Aurelia 2. It is now automatically handled for you by the framework, so now our HTML components look like this.

<bindable name="user" />

<p>${user.name}</p>
<p>${user.email}</p>

Because there is no template tag, you need to create your bindable properties using the bindable element and the name property to specify what it should be called.

Just like Aurelia 1, the file name itself (in our case it is user-info.html) becomes the name of our HTML tag without the .html file extension. If we called it user-block.html our element would be referenced using that name instead.

Importing & Using It

You created a HTML only custom element in Aurelia, now what? Now, you import the component.

<import from="./components/user-info.html"></import>

<user-info user.bind="user"></user-info>

If you want to follow along with a tutorial for creating a simple weather application in Aurelia which involves creating a HTML only custom element and importing it, I have a weather application tutorial here.

Building A Weather Application With Aurelia 2

While Aurelia 2 is still not quite ready for release, you can use it right now as the basic core pieces are functional. I thought it would be fun to build a weather application using Aurelia 2.

If you don’t want to run through a tutorial and just want the final result, all of the code for the weather application can be found on GitHub here.

What Are We Building?

In this tutorial, we are going to be building an Aurelia 2 application that displays weather information. Original, right? You will learn how to create new Aurelia 2 applications, as well as work with the OpenWeatherMap API where we will consume JSON for the information.

Before we can continue, head over to the OpenWeatherMap website here and create a free account. This application will only be for personal use, so the limits of 60 calls per minute are perfect for us.

You will then want to generate an API key by heading over to the API Keys section once you are signed up and logged in.

A Note On Code In This Tutorial

Aurelia allows you to leverage conventions for things such as custom elements, value converters and whatnot. It also allows you to be more explicit in how you name and import dependencies.

For the purposes of this tutorial post, we will be leveraging conventions, but the code in the repository will leverage no conventions and use decorators for describing components. My personal preference is to be quite explicit in my Aurelia applications.

Getting Started

Unlike Aurelia 1, there is nothing to install globally (the aurelia-cli is not a dependency you need any more). To bootstrap a new Aurelia 2 application, you simply open up a terminal/PowerShell window and run:

npx makes aurelia

Because TypeScript is the future, I recommend choosing the “Default TypeScript Aurelia 2 App” option in the prompt. Then choose, “npm” for the package installer option and wait for your app to be created.

To confirm everything installed correctly, open up the generated application directory (in my case it is weather-app) and then run the application using npm start a browser window should open and point to port 9000.

Create A Weather Service

In an Aurelia application, using singleton service classes is a great habit to get into too. Singletons are easy to test and work well with Aurelia’s dependency injection (DI).

In the src directory create a new folder called services and a file called weather-api.ts which will handle making calls to the OpenWeatherMap API service.

import { HttpClient } from '@aurelia/fetch-client';
import { DOM } from '@aurelia/runtime-html';

const http = new HttpClient(DOM);

export class WeatherApi {
    private apiKey = '';
	private units = 'metric';

    public async getWeather(address) {
        const req = await http.fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${address}&units=this.units&APPID=${this.apiKey}`);

        return req.json();
    }
}

This simple service will allow us to query the API for weather information. But, we are not using TypeScript to its full potential here. Let’s write some interfaces and type the response.

import { HttpClient } from '@aurelia/fetch-client';
import { inject } from 'aurelia';

@inject(HttpClient)
export class WeatherApi {
    private apiKey = '';
    private units = 'metric';

	constructor(private http: HttpClient) {

	}

    public async getWeather(latitude: number, longitude: number): Promise<IWeatherResponse> {
        const req = await this.http.fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${latitude}&lon=${longitude}&units=${this.units}&APPID=${this.apiKey}`);

        return req.json();
    }
}

interface IWeatherResponse {
    cod: string;
    message: number;
    cnt: number;
    list: IWeatherResponseItem[];
}

interface IWeatherResponseItemWeather {
    id: number;
    main: string;
    description: string;
    icon: string;
}

interface IWeatherResponseItem {
    dt: number;
    main: {
        temp: number;
        feels_like: number;
        temp_min: number;
        temp_max: number;
        pressure: number;
        sea_level: number;
        grnd_level: number;
        humidity: number;
        temp_kf: number;
    };
    weather: IWeatherResponseItemWeather[];
    clouds: {
        all: number;
    };
    wind: {
        speed: number;
        deg: number;
    };
    rain: {
        '3h': number;
    };
    sys: {
        pod: string;
    };
    dt_txt: string;
}

Now, there is one thing I want to point out with the above example. We’re hard-coding the API key into the singleton class, in a real application, you would and should never do this. Anyone who has your API key will be able to make requests and blast through your limits quickly. Never store API keys client-side.

We now have the class we will use to query for weather information. I won’t go into super specifics around markup and whatnot as those things can be seen in the GitHub repository for this tutorial here.

Leveraging Dependency Injection (DI) To Import Our Service

Now that we have our weather API service, we need to include it for use in our application. We will be editing the generated my-app.ts file as part of the Aurelia application creation process.

We want to replace the entirety of our my-app.ts file with the following:

import { WeatherApi } from './services/weather-api';

export class MyApp {
  private weather;

  constructor(private api: WeatherApi) {

  }

  attached() {
    navigator.geolocation.getCurrentPosition((position) => this.success(position), () => this.error());
  }

  async success(position: Position) {
    const latitude  = position.coords.latitude;
    const longitude = position.coords.longitude;

    this.weather = await this.api.getWeather(latitude, longitude);
  }

  error() {

  }
}

Because my-app.ts is a rendered custom element (as can be seen inside of index.ejs we get DI automatically when we use TypeScript. This means we don’t have to use the inject decorator to inject things.

All dependencies get passed through the constructor and using TypeScript with a visibility keyword, they get hoisted onto the class itself for use. It’s a nice touch and one of my favourite things about TypeScript.

The attached method is a lifecycle method that gets called in components once the DOM is ready. This is where you handle interacting with the DOM or calling various API methods. We call the getCurrentPosition method here to request the users latitude and longitude.

The success callback is called via the navigation position callback on success. This is where we get the latitude and longitude values, then we make a call to our injected API class and call the getWeather method.

You might also notice we are using async/await here which allows us to wait for the results of a promise and get the data. We assign the value to the class variable weather which will be referenced in the view template shortly.

Creating A Value Converter For Formatting Dates/Times

We are going to use the date-fns library for working with dates and formatting them. One of the values the weather API returns is a date string which we will parse and then format for display purposes.

You might not have worked with date-fns before, but it is similar to Moment.js which is a heavier and often unnecessary option to go with.

To install date-fns all we need to do is run:

npm install date-fns

In Aurelia, a value converter is exactly what it sounds like. It converts values to something else (either to the view or from the view). In our use case, we only want to convert a value in the view.

For resources, I highly recommend creating a resources directory which exports an array of resources to make global.

Create a file called src/resources/value-converters/date-format.ts and add in the following:

import { valueConverter } from '@aurelia/runtime';
import { format } from 'date-fns';

export class FormatDateValueConverter {
    toView(date): string {
        return date ? format(new Date(date), 'MM/dd/yyyy - h:mm bbbb') : date;
    }
}

Inside of the resources directory create a file called index.ts with the following:

import { FormatDate } from './value-converters/format-date';

export const resources = [
    FormatDate
];

This exports an array of one or more resources. For the purposes of this tutorial, we are only exporting one resource to make global. In a real application, you might have several. If you worked with Aurelia 1, this paradigm will look familiar with you with an array of resources that get globalised. Except, globalResources is no longer a thing.

Inside of src/main.ts we want to import those resources and register them:

import Aurelia from 'aurelia';
import { MyApp } from './my-app';
import { resources } from './resources';

Aurelia
    .register(resources)
    .app(MyApp)
    .start();

The Markup

We now have the basics in place, let’s start with our markup and styling. We are going to use Bootstrap 4 because it has a good grid system and will make styling things easier.

Install and Configure Bootstrap

npm install bootstrap

Before we start adding in any HTML, we need to import the main Bootstrap CSS file into our application.

At the top of src/main.ts add the following import:

import 'bootstrap/dist/css/bootstrap.css';

We now have the styling we need for marking up our columns and aspects of the grid system.

Creating A Weather Component

Breaking your application into components is a great way to create applications. Smaller components are easier to test, they are also easier to maintain and neater.

Inside of the src directory create a new folder called components and create a component called weather-item which we will import and use to display our weather information.

Now, we want to create the HTML file for our custom element: src/components/weather-item.html

<bindable name="data" />

<p><strong>Date:</strong> ${data.dt_txt | formatDate}</p>
<p><strong>Clouds:</strong> ${data.clouds.all}%</p>
<p><strong>Temperature:</strong> ${data.main.temp}&deg;</p>
<p><strong>Feels Like:</strong> ${data.main.feels_like}&deg;</p>
<p><strong>Humidity:</strong> ${data.main.humidity}%</p>

A brief explanation of what is happening here, we just created a HTML only custom element. The bindable element at the top is telling Aurelia that we have a custom element which accepts a bindable property called data which allows data to be passed through.

You will notice below when we import and use our element, we are binding on the data property by specifying data.bind. Inside of our custom element, we reference this bindable value specifically to get pieces of data passed in.

If you have experience working with other frameworks or libraries such as React, you might know of these as “props” in Aurelia they’re bindable properties.

If you want to build custom elements with business logic that extends beyond simple bindables, you will want to consult the documentation on creating custom elements that leverage a view-model (something we do not need to do here).

<import from="./components/weather-item.html"></import>

<div class="container spacer-v">
    <form class="mb-4">
        <h2 class="mb-3">Weather. Whenever.</h2>
    </form>

    <div if.bind="weather && weather.cod === '404'">
        <h3>Error</h3>
        <p>${weather.message}</p>
    </div>

    <div class="row" if.bind="weather && weather.cod !== '404'">
        <div class="col-md-3">
            <div class="row">
                <div class="col-md-3"><img src="http://openweathermap.org/img/wn/${weather.list[0].weather[0].icon}.png"></div>
                <div class="col-md-8">
                    <h3>${weather.city.name}, ${weather.city.country}</h3>
                </div>
            </div>
        </div>
        <div class="col-md-8">
            <div class="row">
                <weather-item data.bind="item" class="col-md-4 mb-3" repeat.for="item of weather.list"></weather-item>
            </div>
        </div>
    </div>
</div>

The first line is simply using the import element to include our component for use in our view. The import element works like a Javascript import, except it can also import HTML files as well as CSS files. If you have experience with Aurelia 1, this is the same element as require.

The rest is standard Aurelia templating, if you’re familiar with Aurelia v1, this will look familiar to you already.

If you’re new to Aurelia, I highly recommend reading the documentation to get a better understanding of how to author Aurelia templates and work with the templating.

To complete the styling, open up my-app.css which is a CSS file included automatically by Aurelia (matching the name of my-app.ts using conventions).

.spacer-v {
    padding-top: 50px;
}

Running The App

Provided you followed all of the steps correctly, to run the application simply type the following in the project directory:

npm start

A browser window should open and you should see an application that requests your current location and shows you the weather. It should look like this.

There are some improvements you could make on your own like a field that allows users to type addresses, a map or more detailed weather information, adding in routing to view specific fine-grain information. This is a quick and basic tutorial showing you how easy it is to build in Aurelia 2.

Reasons To Use Aurelia in 2020

It is almost the year 2020, and you are still not using Aurelia, say it isn’t so. No more excuses, it’s time to charge up your Bluetooth keyboard and mouse batteries, make yourself a coffee and start using Aurelia.

Version 2 is coming and it’s going to be FAST

While Aurelia 1 is plenty fast, Aurelia 2 is a complete rewrite of Aurelia from the ground up. It not only focuses on JIT (Just In Time) runtime performance but also sees the introduction of AOT (Ahead of Time) compiling support which will yield upwards 100x speed improvements in your applications.

Aurelia 2 will take the learnings of Aurelia 1, along the way the features that many developers love and supercharge them, as well as add in new features that modern web applications require.

Low Learning Curve, Highly Extendable

The low-learning curve of Aurelia is unrivalled by any other framework. Show me a fully-featured client-side framework that can build ambitious large-scale web applications that require minimal documentation diving to use.

I have helped upskill developers from all facets in Aurelia and it truly speaks for itself. Just recently two backend developers at my work started moving into the front-end and within the space of just a week were writing and shipping Aurelia code.

Besides the ease-of-use, the extensibility is once again unrivalled. From the dependency injection through to templating, routing and compiling, every part of Aurelia can be overridden and replaced.

Dependency Injection

There are too many benefits of Dependency Injection to list, but there is no denying that DI is immensely useful and powerful. Aurelia has a great DI layer allowing you to pass around dependencies in your applications and specify the type of injection mode they should use.

One of the great benefits of Dependency Injection is unit testing. Because dependencies are passed through the constructor in your components and view-models, it allows you to easily mock them or my favourite approach of overriding the value in the container with a mocked version.

While it is possible to shoe-horn some semblance of DI into other libraries and frameworks, Aurelia provides a true Dependency Injection layer which can be used in your applications and keeping in line with the mantra of “easy to override” you can configure whatever way you want too.

First-class TypeScript Support

I have been working with Aurelia since 2015, I have been using it with TypeScript since 2016 and Aurelia has always supported TypeScript without the need for anything additional to be installed. The framework ships with strong typing support and in Aurelia 2, TypeScript is even more supported. The codebase of Aurelia 2 is completely written in TypeScript.

Long-term Support // Minimal Breaking Changes

Some of us Aurelia veterans have been running production applications since 2015 when it was an alpha release. As time went on and Aurelia reached beta, then release candidate stages before stable 1.0, while the framework was improved and changed, the core design stayed the same.

In its almost five years of existence, there has not really been one single breaking change. The core architecture and vision of Rob has remained untouched. There are not many frameworks and libraries that can boast continual improvement without some form of breaking change or convention.

Flexible Binding Approaches

Despite what some developers believe, there is no denying that two-way binding is amazing if used correctly. The ability to bind values to a view-model from a form input is immensely powerful. Unlike something like React which forces you to litter your code with change function callbacks to update values.

  • One way
  • Two way
  • From view
  • To view
  • One time

Batteries Included

Why waste your time deciding what Router library to use, what state management solution you should use, whether you want to write in some XML like HTML syntax or how you will deal with validating some form inputs?

Aurelia is a glue-less framework that provides you with all of the modules you’ll need to build web applications. Let’s not get it twisted, it is quite rare that you just need the view component, most web applications we build generally require routing, validation, state management and templating.

Do you really want to wake up to the sound of tears on Christmas day because you forgot to buy the batteries and all of the shops are closed?

Some Small Blog Changes Preempting Aurelia 2

As Aurelia 2 draws near, I have made some changes to my blog. Acknowledging that many of you rely on my blog as a source of information and help with Aurelia 1, I have created an Aurelia 2 category and renamed the existing category to Aurelia 1.

This will hopefully alleviate any confusion that you might have when Aurelia 2 is released. While many of my Aurelia 1 articles will still be relevant, they might not always apply to the new version of Aurelia.

Until Aurelia 2 is released, these changes do not currently mean much. But, after release, they will.

Another change you might have noticed is a new theme. The existing theme served me well for years, but now, it is time to try something newer and still easy to read. I am using the Less theme.