Side-by-side comparison

Bootstrapping

The hosting page

The first entry point of an Aurelia application is the main HTML page-loading and hosting.

<!-- index.ejs -->

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <title>Aurelia</title>
   </head>
   <body aurelia-app="main">
      <script src="scripts/vendor-bundle.js"
         data-main="aurelia-bootstrapper"></script>
   </body>
</html>

aurelia-app attribute helps us to introduce our entry point, themain.tsfile, which includes the configurations of the project.

The main module

All the initial settings for starting and working with an Aurelia project are done in this file.

// src/main(.js|.ts)

export function configure(aurelia: Aurelia): void {
  aurelia.use
    .standardConfiguration()
    .feature(PLATFORM.moduleName('resources/index'))
    .globalResources(PLATFORM.moduleName('./bar/nav-bar'));

  aurelia.use.developmentLogging(environment.debug ? 'debug' : 'warn');

  if (environment.testing) {
    aurelia.use.plugin(PLATFORM.moduleName('aurelia-testing'));
  }

  aurelia.start()
         .then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
}

What does PLATFORM.moduleName do?

Whenever you reference a module by string, you need to usePLATFORM.moduleName("moduleName")to wrap the bare string. PLATFORM.moduleName is designed to teachWebpackabout Aurelia's dynamic loading behavior.

What is a globalResources?

When you create a view in Aurelia, it is completely encapsulated so you mustrequirecomponents into an Aurelia view. However, certain components are used so frequently across views that it can become very tedious to import them over and over again. To solve this problem, Aurelia lets you explicitly declare certain "view resources" as global.

What is a feature?

Sometimes you have a whole group of components or related functionality that collectively form a "feature". This "feature" may even be owned by a particular set of developers on your team. You want these developers to be able to manage the configuration and resources of their own feature, without interfering with the other parts of the app. For this scenario, Aurelia provides the "feature".

What is a plugin?

Similar to features, you can install 3rd party plugins. The main difference is that a "feature" is provided internally by your application, while a plugin is installed from a 3rd party source through your package manager.

What does setRoot() do?

Instantiates the root component and adds it to the DOM.

Components

The Root Component

The root of any Aurelia application is a single component, which contains everything within the application, actually, the root component.

<!-- View -->
<!-- src/app.html -->

<require from="./styles.css"></require>
<require from="./nav-bar.html"></require>
<template>
    <h1>${message}</h1>
</template>
// ViewModel
// src/app(.js|.ts)

export class App {
    constructor() {
        this.message = 'Hello World!';
    }
}
  • To import any style, component or etc, you should userequire.

  • Wrapping the whole HTML content viatemplateisnecessary.

The Component Life-cycle

Every component instance has a life-cycle that you can tap into. This makes it easy for you to perform various actions at particular times

NameAurelia 1AsyncableDescription

constructor

constructor

define

hydrating

hydrated

created

created

binding

bind

bound

attaching

attached

attached

detaching

unbinding

unbind

dispose

Aurelia 1 has a restriction and the community made an afterAttached plugin that is called after all child components are attached, and after all two-way bindings have completed. Theattachedlife-cycle in version 2 covers this scenario.

Which life-cycle hooks are most used?

Such cases can be summarized.

NameWhen using it

binding

Fetch data (working with API services & Ajax calls), initialize data/subscriptions.

bound

Any work that relies on fromView/twoWay binding data coming from children, Defining router hooks.

attached

Use anything (like third-party libraries) that touches the DOM.

unbinding

Cleanup data/subscriptions, maybe persist some data for the next activation.

dispose

One way cleanup all the references/resources. This is invoked only once and is irreversible

Dependency injection

A dependency injection container is a tool that can simplify the process of decomposing such a system. Oftentimes, when developers go through the work of destructuring a system, they introduce a new complexity of "re-assembling" the smaller parts again at runtime. This is what a dependency injection container can do for you, using simple declarative hints.

Registering services

Aurelia 1Aurelia 2Description

container.createChild()

DI.createContainer()

-

container.registerSingleton(key: any, fn?: Function)

Registration.singleton(key: any, value: Function): IRegistration

-

container.registerTransient(key: any, fn?: Function)

Registration.transient(key: any, value: Function): IRegistration

-

container.registerInstance(key: any, instance?: any)

Registration.transient(key: any, value: any): IRegistration

-

container.registerHandler(key, handler)

Registration.callback(key: any, value: ResolveCallback): IRegistration

-

container.registerResolver(key: any, resolver: Resolver)

container.registerResolver(key: any, resolver: IResolver)

-

container.autoRegister(key: any, fn?: Function

-

Registration.alias(originalKey: any, aliasKey: any): IRegistration

-

Resolving services

Aurelia 1Aurelia 2Description

container.get(MyService)

container.get(MyService)

-

container.getAll(MyService)

-

Registration strategies

NameAurelia 1 & 2Description

@singleton

-

@transient

-

Resolvers

// Aurelia 2
import { inject, lazy, all, optional, newInstanceOf, factory } from "@aurelia/kernel";
Aurelia 1Aurelia 2Description

@inject(MyService)

@inject(MyService)

-

@autoinject()

@inject(Lazy.of(MyService))

@inject(lazy(MyService))

-

@inject(All.of(MyService))

@inject(all(MyService))

-

@inject(Optional.of(MyService))

@inject(optional(MyService))

-

@inject(Parent.of(MyService))

-

@inject(Factory.of(MyService))

@inject(factory(MyService))

-

@inject(NewInstance.of(MyService))

@inject(newInstanceForScope(MyService))

-

@inject(newInstanceOf(MyService))

-

Logging

Writing debug output while developing is great. This is how you can do this with Aurelia.

Write an appender.

export class ConsoleAppender {
    debug(logger, ...rest) {
        console.debug(`DEBUG [${logger.id}]`, ...rest);
    }
    info(logger, ...rest) {
        console.info(`INFO [${logger.id}]`, ...rest);
    }
    warn(logger, ...rest) {
        console.warn(`WARN [${logger.id}]`, ...rest);
    }
    error(logger, ...rest) {
        console.error(`ERROR [${logger.id}]`, ...rest);
    }
}

In the main(.js|.ts)

import * as LogManager from 'aurelia-logging';
import { ConsoleAppender } from 'aurelia-logging-console';
export function configure(aurelia) {
    aurelia.use.standardConfiguration();

    LogManager.addAppender(new ConsoleAppender());
    LogManager.setLevel(LogManager.logLevel.debug);

    aurelia.start().then(() => aurelia.setRoot());
}

Router

Routing Life-cycle

NameDescription

canActivate

if the component can be activated.

activate

when the component gets activated.

canDeactivate

if the component can be deactivated.

deactivate

when the component gets deactivated.

Binding

String Interpolation

NameAurelia 1 & 2Description

${ }

Binding HTML and SVG Attributes

NameAurelia 1 & 2Description

one-way

to-view

from-view

two-way

one-time

bind

References

| Name | Aurelia 1 | Aurelia 2 | Description | | ---- | - | - | | ref | | | | | view-model.ref | | | deprecated in v2 | | component.ref | | | Not in v1 |

Passing Function References

NameAurelia 1 & 2Description

call

DOM Events

NameAurelia 1 & 2Description

trigger

delegate

capture

{% hint style="info" } In v2, if an expression return a function, that function will be use as the handler for the event. V1 only evaluates the expression. {% endhint }

Contextual Properties

General

NameAurelia 1 & 2Description

$this

The view-model that your binding expressions are being evaluated against.

Event

NameAurelia 1 & 2Description

$event

The DOM Event in delegate, trigger, and capture bindings.

Repeater

NameAurelia 1Aurelia 2Description

$parent

$parent.$parent.$parent.name

$index

$first

$last

$even

$odd

$length

@computedFrom

@computedFrom tells the binding system which expressions to observe. When those expressions change, the binding system will re-evaluate the property (execute the getter).

Aurelia 1Aurelia 2

In Aurelia 2, The framework automatically computes observation without the need for any configuration or decorator.

Observation in template

typeexampletypeAurelia 1Aurelia 2

property

${a}

syntax:

observation:

member

${a.b}

syntax:

observation:

value conveter

${a | convert: value }

syntax:

observation:

binding behavior

${a & behavior: config }

syntax:

observation:

function call

${doThing(param)}

syntax:

observation:

array methods

${items.join(', ')}

syntax:

observation (on array):

lambda

${items.filter(x => x.v > 70)}

syntax:

observation:

@attributePattern

This feature is totally new for Aurelia 2.

// Angular binding syntax simulation

// <input [disabled]="condition ? true : false">
@attributePattern({ pattern: '[PART]', symbols: '[]' })
export class AngularOneWayBindingAttributePattern {
    public ['[PART]'](rawName: string, rawValue: string, parts: string[]): AttrSyntax {
        return new AttrSyntax(rawName, rawValue, parts[0], 'one-way');
    }
}

// <input [(ngModel)]="name">
@attributePattern({ pattern: '[(PART)]', symbols: '[()]' })
export class AngularTwoWayBindingAttributePattern {
    public ['[(PART)]'](rawName: string, rawValue: string, parts: string[]): AttrSyntax {
        return new AttrSyntax(rawName, rawValue, parts[0], 'two-way');
    }
}

// <input #phone placeholder="phone number" />
@attributePattern({ pattern: '#PART', symbols: '#' })
export class AngularSharpRefAttributePattern {
    public ['#PART'](rawName: string, rawValue: string, parts: string[]): AttrSyntax {
        return new AttrSyntax(rawName, parts[0], 'element', 'ref');
    }
}

Last updated