Callback Functions in Aurelia Using .call

Aurelia’s robust binding system allows you to not only bind values into your custom attributes and elements, but also the ability to pass in callback functions as well. While your first instinct might be to try using <my-element callback.bind="myFunction" you will quickly realise that this will not work because of scoping issues.

This is where .call comes in. Using .call allows you to pass in callback functions to your bindables, and when they get called, their scope is retained.

Callbacks Without Parameters

Say we have a custom element we have created called my-custom-element and it has a bindable property called callback defined inside of the view-model using

@bindable callback = () => {}

Then our custom element callback binding looks like this:

<my-custom-element callback.call="someCallbackFunction()">

Inside of our custom element, when the callback bindable is fired, it will call our callback function and the scope of someCallbackFunction will be retained (the view-model it is defined in).

When you are not using parameters things are easy enough. You just need to define your callback with the circular function brackets like you would if you’re using click.delegate or other more event-type bindings.

Callbacks With Parameters

This is where I see developers get caught out quite a bit, passing parameters to callback functions. Using our above function, let’s say that our callback accepts two parameters: user and item.

<my-custom-element callback.call="someCallbackFunction(user, item)">

Inside of your custom element, when you call the callback you might try something like this if you didn’t read or understand the documentation correctly:

this.callback(this.selectedUser, this.selectedItem)

Because of how the .call feature works, this will not work (as you might have possibly already discovered). This is because you need to pass an object to the callback with your parameters matching the names you use in your HTML.

In our case, we are expecting two parameters: one called user and one called item to be passed into the callback.

Inside of our custom element, we need to pass them like this:

this.callback({user: this.selectedUser, item: this.selectedItem})

Now, our values get passed correctly and the callback retains its scope.

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.

Implementing A Method To Get Single Values In Aurelia Store

The Aurelia Store plugin is a great way to add powerful and easy to use state management into your Aurelia applications. For some, the paradigm shift in how you work can be confusing to work with at first. One such task you might find yourself needing to do is obtaining a singular value from the state.

As you will soon discover, state management in Aurelia Store requires you to subscribe to the entire state and react to all changes. Sometimes you just want to get a single value from the state to reference inside of your view-models.

While I cannot guarantee Vildan (Aurelia core team member and author of Aurelia Store) will approve of my solution, it works 😂

The solution I came up with which fits my needs perfectly is a method to subscribe, get one or more values from the state and then unsubscribe.

export const getStatePropertyOnce = async (...properties: string[]) => {
  return new Promise(async (resolve, reject) => {
    const subscription = store.state.pipe(pluck(...properties)).subscribe(
      (value) => { resolve(value); },
      (error) => { reject(error); }
    );
    subscription.unsubscribe();
  });
};

The beautiful thing about this method is it not only supports top-level properties, but it also works for nested properties in your state object as well. In a real use case, I have the locality value of the user’s client stored in the state.

async getAppClient() {
    this.appClient = await getStatePropertyOnce('appClient');
} 

There might be some pitfalls I have yet to encounter with the above functionality and you should also make sure your await is wrapped in a try/catch block as well to handle errors, but it works for my needs. If the thought of having to use @connectTo or manually setup a subscriber and then dispose of it within your view-models sounds like a lot of work, this helper method can be a good time saver.

async getValueFromStore() {
    // Object in state is represented as user.details.email
    this.someValue = await getStatePropertyOnce('user', 'details', 'email');
} 

In the above example, we are using the method to get a property of email which exists on an object called details which lives inside of a main user object. The method handles getting nested properties with ease.

What I Love About Aurelia

There is no shortage of Javascript frameworks and libraries to choose from. Notably, you have Angular, React, and Vue, which are the most discussed and used.

If you are a regular reader of my blog, you know how much I love Aurelia and have blogged about it since early 2015. If you are new, let me quickly introduce myself.

I have been a developer for 11 years now, working in the front-end space. My experience stems back to the likes of; ExtJS, YUI, Backbone, Knockout, Durandal and Angular v1. Believe it or not, I also used to work with React back in 2014/2015.

I still remember seeing the post on Hacker News announcing the Aurelia alpha release. The date was January 26th, 2015. After reading through the website and goals of the framework as well as being familiar with Rob’s previous work, I gave it a go and never looked back.

Since 2015, I have been working with Aurelia daily in my day job (current job as well as my previous job) as well as side-projects and random ideas; there isn’t a project that I haven’t used it on.

Aurelia promotes strong separation of concerns

When I first started in web development, the one thing ingrained into me from the beginning was: separation of logic and templating, or separation of styles and markup also known as Separation of Concerns (SoC).

Web pages by their natural order promote separation by concern. HTML is used to structure and define the page; CSS is used to style the HTML and Javascript responsible for page interaction and logic.

In Aurelia, your business logic gets handled within a view-model, markup handled inside of a view and styling is handled inside of a stylesheet. When you think about it, Aurelia doesn’t try replacing what browsers and specs already give you; it enhances them.

Separation of concerns is a repeated theme throughout the framework. Components, custom attributes and routed views all utilise the same conventions and approach to writing a web application.

Think about how you would develop a web application or page without a framework these days, and it would be an HTML file for the markup, a stylesheet for the styling and a Javascript file which contains any logic for interacting with the page or dealing with data. No conventions, just basic concepts that never change, this is what it is like building in Aurelia.

I do not want to turn this post into a framework/library bashing contest, but this is one of the things I dislike about React. It reminds me of working with PHP applications (not using a framework) where business logic, styling and markup are all intertwined with one another.

There might be other ways these days with later versions of React, but the basic premise is you stuff a bunch of XML like HTML (JSX) inside of a render function which is called by React. You break up you UI into smaller components and use props to pass data through to them. While JSX is not required, it is the most commonly used syntax I have seen for authoring React components.

Let me acknowledge that A) I haven’t worked with React in a few years and B) I am biased because of my use of Aurelia. Please correct me if any of my assumptions and claims about React are inaccurate, and I can amend them.

Batteries included, no glue required

One of my absolute favourite things about Aurelia is the fact it gives you almost everything you need out-of-the-box. It gives you powerful templating, API’s, dependency injection, routing.

Then you have the plethora of plugins on offer for other functionality. Want to use Fetch with more beautiful syntax and error handling? Aurelia Fetch Client. Want to localise your application into other languages? Aurelia i18n. Need a configurable modal in your application? Aurelia Dialog.

If you want to add in state management to your Aurelia application and don’t want to get a frontal lobotomy using something over-engineered and complicated like Redux, there is Aurelia Store which is an RxJS powered state management library compatible with the Redux Dev Tools browser extension.

In my experience working with other frameworks and libraries; some require glueing together a lot of independently maintained dependencies to build what is essentially a framework.

Why waste your time creating a framework piece-by-piece every single time you want to build something. Save yourself the node_modules weight and time, use something that gives you what you need straight away.

Aurelia can be used without needing a bundler or build process

If your experience goes as far jQuery where you drop in a script and start writing code, then the ability to use Aurelia in script form might appeal to you. Thanks to Aurelia Script, you can add in a script and starting authoring powerful web applications.

Not only is this approach useful for quick prototyping on Codepen or Codesandbox, it means you spend less time battling with complicated build process in Webpack and fixing complex issues and extension incompatibilities.

If I am honest, not many of us enjoying configuring Webpack, opting to pull out our teeth with a pair of pliers instead.

It has no Virtual DOM

Thanks to other popular frameworks and libraries, the words Virtual DOM have become synonymous with developers naively believing that it means fast applications. While the Virtual DOM is impressive from a technical perspective, it’s not the only way to achieve fast performing web applications.

In Aurelia, the binding system is reactive; this means that when something changes, it gets updated in your view. Because there is no Virtual DOM, you’re working with just the real DOM, and you can use third-party libraries which need to touch the DOM without any problems.

The more you read into what a Virtual DOM is and how it works, the more you realise it’s not necessarily always the most performant choice.

It’s easy for newcomers and all skill level developers

I have seen developers upskill in Aurelia from a multitude of levels. I have seen back-end developers grasp Aurelia in a few days, I’ve seen front-end developers used to working with jQuery or React also get it quickly, and I have seen newcomers grasp it equally as fast.

I think this is a unique selling point for Aurelia; you don’t need a PhD in Javascript to know what is going on with it. Its conventions based approach means you spend less time configuring Aurelia and more time writing code.

The Aurelia CLI is fantastic

All useful frameworks and libraries these days have a CLI which allow you to get a starting application up and running with the features and coding styles needed: Aurelia is no exception.

There isn’t anything unique about the Aurelia CLI, but it makes your life a lot easier when you’re building a new project.

Familiar syntax, aligned with standards

In an era where framework and library authors are reinventing the wheel or introducing foreign concepts not found in any specification, Aurelia goes against the grain by leveraging standards-based concepts and API’s.

The templating syntax for displaying a value uses the same interpolation syntax ${myVariable} that you would inside of template literals inside of your Javascript/TypeScript code. Binding to properties is equally as intuitive, want to bind a value on a form input? <input type="text" value.bind="bindToThis">

If you want to use Web Components with Aurelia, there is a plugin for that and the next version; Aurelia will be aligned with the HTML Modules specification to give you single-file components like you might find in Vue, only standards-based.

This is one of the most unique features and selling points of Aurelia. It allows developers to work in a way that is familiar, a way that requires very little buy-in with the intent to eventually allow official specifications to replace features found in Aurelia.

Working With An API In Aurelia Store

Unless you’re working on a completely static web application, chances are you’ll be needing to get data from an API or send data to one. In Aurelia, you would usually do this either using the HTTP Client or Fetch Client (you should be using Fetch). However, what about Aurelia Store? The versatile state management library for Aurelia.

You have two approaches you can take when using Aurelia Store with an API, and we’ll discuss the pros and cons of each one. This article is going to be a small and relatively non-technical article.

Make API requests from within your actions

Aurelia Store supports asynchronous actions, meaning you can delay their execution until the async function promise resolves. A simple Aurelia store action might look like this if using async.

async function myAction(state) {
    const newState = { ...state };

    // Do something in here

    return newState;
}

When you return from within an async function, it’s akin to a Promise.resolve the entire function itself becomes wrapped in a promise, but we’re not going to go into specifics of how async/await works in this post.

Making a function async means, you can call an API from within your action and then store the result in your state when it loads. This simplified code assumes that you’re accounting for errors in the loadUsers, hence there not being a try/catch block below.

async function myAction(state) {
    const newState = { ...state };

    newState.users = await api.loadUsers();

    return newState;
}

This approach works well because it means you can load data through actions, they are easier to debug, and you can perform transformations on the data returned. It also makes refactoring your code so much easier as you only need to change one action.

However, the downside is if the request above takes longer than expected. Maybe you’re using an Azure or Google Cloud Function (lambda function), and it takes a few seconds to start because it’s not warmed up, this request might take a few seconds to complete and meanwhile, your application slows down to a crawl. If you’re calling multiple actions, it’ll delay calling the other actions until the current one returns a state.

If you keep an eye on your actions and ensure the requests are tiny, then this should never be a problem. Adding a visual loading indicator into the application can also alleviate any loading issues. However, assumption-led decision making can sometimes backfire.

API Call First, Dispatch Action Second

In the above approach, the request and action are one function. In this approach, you request the data first and then dispatch an action after.

There is an obvious upside to this approach. Your actions execute fast; they don’t have to wait for API calls to resolve before continuing. Another upside is that it ensures your state layer and API logic remains separate. The maybe not-so-obvious downside is you now have to write and maintain two different pieces of code.

async function myAction(state, users) {
    const newState = { ...state };

    newState.users = users;

    return newState;
}

async function loadUsers() {
    const request = await fetch('/users/all');
    const response = await request.json();

    return response;
}

export class ViewModel {
    async activate() {
        const users = await loadUsers();
        dispatchify(myAction)(users);
    }
}

But, which one do I use?

The point of this post is not to tell you that you should use one over the other; it is to point out that the two approaches have upsides and downsides. Either all is fine, you only need to be aware of the caveat of async actions. When you create an asynchronous function, they all become async.

I use the second approach in my Aurelia applications. I like decoupling my state management from my API logic completely. It means if I want to remove state management at a later date or use something else, there is no tight coupling in my code. Remove my actions and call the API functions myself from my view-models (or wherever).

Masked Inputs In Aurelia: The Easy (and reliable) Way

When it comes to adding in masked inputs into a modern Javascript web application, it is easier said than done. The task at hand is simple, yet, under the surface is paved with complexity in a framework with unidirectional data flow.

The problem I am going to describe is also a problem you’ll encounter in Angular, Ember, Vue and any other framework or library which offers two-way binding on input elements or modifying the input itself.

The Problem

You have an input element. You want users to be able to enter a value and automatically format it as they type. This input could be anything, but in my situation, the input was for entering numeric values.

I wanted the value to automatically add a comma for the hundreds, add two decimals to the end and a dollar sign ($) symbol as a prefix to the value.

By default in Aurelia, binding on input elements is two-way. This means the value is both updated in the view and view-model, which in many cases is great.

As you can imagine, in the case of wanting to format an input element automatically you are instantly fighting with the framework. The problem is the plugin that does the formatting is modifying the input, and Aurelia itself is also modifying the input.

Why not a value converter?

You can create a value converter (my first attempt) and leverage the toView and fromView methods for mutating the values going to and from the view.

A value converter gets you quite a lot of the way, but one problem you will encounter is the caret position will jump to the end. When the value is modified in the input, the entire input is effectively refreshed and the cursor jumps to the end of the value which is jarring and annoying.

How about a custom attribute?

My second attempt involved using a custom attribute that listened to the input and blur events. I added in some checks of the value and attempting to work around the caret position by reading it whenever the input was modified and setting the position after.

Ultimately, I fell into some of the same problems the value converter presented to me. Getting and setting the caret position is tricky business and something I ideally do not want to maintain in the long-term, having to work around issues in different browsers is another problem there.

I knew the only solution had to be leveraging an existing input mask library. A library which supports a plethora of formatting options, masks, working with currencies and other types of data and most importantly: solves the caret jumping problem.

The Solution

I tried a lot of different approaches, referencing implementations for not only Aurelia but Angular and Vue as well. However, the common theme in many of these solutions is they were very complicated. One such plugin I found was over 600 lines of code, many of those specifically for getting and setting the caret.

The final solution ended up being laughably simple, in hindsight. I will show you the code and then run through it below. I am using the inputmask plugin which is a battle-tested and highly configurable input masking plugin.

Whatever library you choose to use, the code will end up looking the same if you follow the approach I have taken.

import { inject, customAttribute, DOM } from 'aurelia-framework';

import Inputmask from 'inputmask';

@customAttribute('input-mask')
@inject(DOM.Element)
export class InputMask {
  private element: HTMLInputElement;

  constructor(element: HTMLInputElement) {
    this.element = element;
  }

  attached() {
    const im = new Inputmask({
      greedy: false,
      alias: 'currency',
      radixPoint: '.',
      groupSeparator: ',',
      digits: 2,
      autoGroup: true,
      rightAlign: false,
      prefix: '$'
    });
    
    im.mask(this.element);
  }
}

export class CleanInputMaskValueConverter {
  fromView(val) {
    if (typeof val === 'string' && val.includes('$')) {
      // Strip out $, _ and , as well as whitespace
      // Then parse it as a floating number to account for decimals
      const parsedValue = parseFloat(val.replace('$', '').replace(/_/g, '').replace(/,/g, '').trim());

      // The number is valid return it
      if (!isNaN(parsedValue)) {
        return parsedValue;
      }
    }

    // Our parsed value was not a valid number, just return the passed in value
    return val;
  }
}

export class PrecisionValueConverter {
  toView(val, prefix = null) {
    const parsedValue = parseFloat(val);

    if (!isNaN(parsedValue)) {
      if (prefix) {
        return `${prefix}${parsedValue.toFixed(2)}`;
      } else {
        return parsedValue.toFixed(2);
      }
    }

    return val;
  }
}

The solution in its simplest terms is three parts:

  • A custom attribute applied to input elements called input-mask which instantiates the plugin and applies the masking options
  • A value converter which strips away any fragments of the mask; $, _ and ,, trims whitespace and then parses the value using parseFloat
  • A value converter which formats a value passed from a view-model and adds a prefix (if specified) and converts the value to a precision of 2 decimal places

During this exploration phase, I stumbled upon a powerful and awesome feature in Aurelia that I did not even know was possible, multiple value bindings. You will notice below that I have a value.one-time as well as a value.from-view binding on the input.

The reason for this was I wanted to initially set the value and then not worry about syncing it again. This allows data loaded from the server to be passed in (initial values, etc). The value.from-view binding updates our view-model every time the value changes.

<template>
    <input 
        type="text"
        value.one-time="value | precision" 
        value.from-view="value | cleanInputMask"
        input-mask>
</template>

It makes a lot of sense that you can do this, but it’s not a documented feature and initially, I wasn’t 100% confident it would work. I am an experimenter, so the worst-case scenario was it wouldn’t work. This is what I love about Aurelia, it can handle anything that you throw at it, even things you think might not work, but end up working.

Basically, this approach creates an inline binding behaviour where you control the direction of the updating process, which is quite powerful and cool.

A great addition to Aurelia itself could be a binding attribute which offers this functionality (allowing a once to view and always from view mode).

Conclusion & Demo

The end result can be seen here, as you can see we have a nicely formatted as you type input element. This was built for a specific use-case so it is missing configuration options, however, I have created a repository here which will have a plugin-friendly version of this soon.

Saved By The Aurelia Portal Attribute

Recently at my day job, I encountered a very specific scenario that I wrestled with for quite a bit. I had a routed set of views, which were using a layout view template because it needed a very specific markup for positioning using CSS Grid.

The issue I had was although the route layout had a <slot></slot> element inside of it for projecting the routes, I wanted a custom navigation element to be projected inside of the routed view. Previously there was a bit of duplication to add the custom element into the right area.

I initially tried to use router View Ports to achieve the result I needed, but they’re more designed for rendering sub-views within a view, I needed to render a component into a specific area of the page and have it react to route change events.

Then I remember the Portal attribute by core team member Binh Vo, it has actually been around for a while now. I haven’t had a need for this plugin, until now. In my situation, I needed to leverage the target property of the attribute to tell it where to inject my custom element and everything worked as expected.

My layout view simplified looks like this:

<section>
    <main-nav></main-nav>
    <inner-nav portal="target: #nav-slot;"></inner-nav>
    <slot></slot>
</section>

For each routed view the simplified markup looks like this:

<template>
  <main>
    <div class="dashboard-wrapper">
      <div class="inner-content">
        <section>
          <div id="nav-slot">
            <div class="content">
                <h1>Some content</h1>
            </div>
          <div>
        </section>
      </div>
    </div>
  </main>
</template>

When this routed view is loaded, the portal attribute will inject the element from the router layout into the DIV with the ID nav-slot. Super simple stuff and it does exactly what I needed it to do. The portal plugin can be found on GitHub here and it’s great to see how it all functions behind-the-scenes. A demo of the plugin in action can also be found here.

Creating Your Own Javascript Decorators in Aurelia

Decorators are currently a stage 2 proposal in Javascript and they allow you to decorate classes, class properties and methods. If you have worked with Aurelia for longer than 5 minutes or other frameworks such as Angular, you will already be familiar with them.

At the core of a decorator, it is a function that returns a function. It wraps the context of wherever it is applied. Decorators allow you to add new properties/methods to a class or change existing behaviours.

Aurelia already utilises decorators quite extensively, but it does not rely on them for everyday use. The existence of decorators allows you to mark your applications up using convenient shorthand.

It is important to remember that decorators are a Javascript language construct and not specific to any framework like Aurelia. Given Aurelia leverages ES2015 classes, we can create and use our decorators without changing anything.

Decorator Types

When we talk about decorators, there are three categories. A class decorator (decorates a class), a class field decorator (inline properties on classes) or a method decorator (a function, either standalone or within a class). You can even create a decorator that combines all three types into one. For the context of this article, we will only be focusing on class decorators.

Creating a class decorator

If you have used Aurelia a little bit, decorators such as; @inject, @singleton and @customElement might be familiar to you already. These are examples of a class decorator.

The inject decorator is used in the following manner:

import {inject} from 'aurelia-framework';
import {Router} from 'aurelia-router';

@inject(Router)
export class MyClass {
    ...
}

If you look at the actual implementation for the inject decorator in the Aurelia codebase here you will notice that a class property called inject is being assigned on the class here.

Because decorators in Aurelia are optional and nothing more than convenient shortcuts, you can write the above like this:

import {Router} from 'aurelia-router';

export class MyClass {
    static inject = [Router];
}

Let’s create a simple decorator that adds a property to our class called isAwesome a boolean property which will get set on the class itself.

@isAwesome(true)
export class MyClass {

}

function isAwesome(val) {
    return function(target) {
        target.isAwesome = val;
    }
}

In the context of this decorator, target is the class we are using the decorator on and gives us access to the class itself, including the prototype object.

Creating an Aurelia decorator

The above decorator is quite simple. It adds a property to our class and does not do anything exciting. Now, we are going to be creating a decorator which shorthands the Aurelia router lifecycle method canActivate.

function canActivate(val, redirectTo = '') {
    return function(target) {
        target.prototype.canActivate = () => {

            if (!val) {
                if (redirectTo === '') {
                    window.location.href = '/404';
                } else {
                    window.location.href = redirectTo;
                }
            }

            return val;
        };
    };
}

While this is a very rough decorator that would need some improvement before serving a genuine purpose, it showcases how you can modify a class, even adding new methods to the prototype with ease.

Now, let’s clean it up and make it more useful and delightful to look at using some nice new Javascript syntax.

const canActivate = (resolve) => {
    return (target) => {
        target.prototype.canActivate = () => {
            return resolve();
        };
    };
};

Now, we have to pass through a function which allows us to be more flexible in what we can pass through. Still, it could be a lot more useful. What if we wanted to access the current route or get passed in parameters like we can with a class defined method?

const canActivate = (resolve) => {
    return (target) => {
        target.prototype.canActivate = (params, routeConfig, navigationInstruction) => {
            return resolve(params, routeConfig, navigationInstruction);
        };
    };
};

Okay, now we have a decorator which accepts a callback function and has access to the route parameters, the routeConfig and current navigation instruction.

To use our new fancy decorator, we pass through a function which needs to return a value (boolean, redirect):

@canActivate((params, routeConfig, navigationInstruction) => {
    return !(routeConfig.auth);
})
export class MyClass {

}

Apply this decorator will deny the class getting activated if the route has an auth property of true. We inverse the boolean check when we return it.

Just when you thought we couldn’t improve our decorator anymore, you might have noticed there is a flaw in what we have created. It always assumes that our callback returns something. If it doesn’t, we’ll stop the view-model from executing.

Let’s tweak our decorator slightly:

const canActivate = (resolve) => {
    return (target) => {
        target.prototype.canActivate = (params, routeConfig, navigationInstruction) => {
            let resolveCall = resolve(params, routeConfig, navigationInstruction);

            return typeof resolveCall !== 'undefined' ? resolveCall : true;
        };
    };
};

We still require a callback function, but if the developer doesn’t return anything from their callback function, we’ll return true as to ensure the view-model executes fine.

If you wanted to redirect all visitors to a different route if it’s an authenticated route, you could do something like this:

import {Redirect} from 'aurelia-router';

@canActivate((params, routeConfig, navigationInstruction) => {
    return (routeConfig.auth) ? new Redirect('/robots') : true;
})
export class MyViewModel {

}

You would want to add in some additional logic to check if a user is logged in and then redirect accordingly, our example does not accommodate for this. We have just showcased how easy it is to write a decorator which can leverage existing methods and properties, as well as defining new ones.

Creating a decorator that sets the title based on the current route

When it comes to setting the title of the page based on the current route, it can be confusing for newcomers. So, using what we have learned, we are going to create a decorator which allows us to set the title from within a view-model in an Aurelia application.

We want to create a class decorator which hooks into the activate method and accesses the routeConfig, which contains the current navigation model and a method for setting the title.

Our decorator should support passing in a function which returns a string value or the ability to pass in a string directly.

const setTitle = (callbackOrString) => {
    return (target) => {
        ((originalMethod) => {
            target.prototype.activate = (params, routeConfig, navigationInstruction) => {
                let newtitle = typeof callbackOrString === 'function' ? callbackOrString(params, routeConfig, navigationInstruction) : callbackOrString;
                
                if (newtitle !== null && newtitle) {
                    routeConfig.navModel.setTitle(newtitle);
                }

                if (originalMethod !== null) {
                    originalMethod(params, routeConfig, navigationInstruction);
                }
            };
        })(target.prototype.activate || null);
    };
};

One important thing to note is our callback function (if one is passed in) gets the same arguments that the activate method does. This means we get parameters, the current route configuration and navigation instruction.

Using it

Assuming you have imported the decorator above or it exists in the same file as your view-model, let’s show how this decorator is used.

Callback function

We pass in a function which returns a string. This scenario might be helpful if you want to determine if the current user is logged in and display their name in the title.

@setTitle((params, routeConfig, navigationInstruction) => { return 'My Title'; }) 
export class MyViewModel {

}

String value

Passing in a string value will just set the page to this string without the use of callback functions. Useful for pages which don’t need dynamic titles.

@setTitle('My Title') 
export class MyViewModel {

}

Conclusion

In this article, we didn’t even cover the full scope of what you can do with decorators. We have only just scraped the surface. In future articles, we might explore other types of Javascript decorators. All you need to remember is decorators are functions which “decorate” whatever they’re being used with.

As a further exercise, maybe think of other things you can write decorators for, to save you some time.

Further reading

Announcing My New Book: Mastering Aurelia Store

I have been working with Aurelia Store these past few months and at one point, I decided that it would be a great idea to write a book on how to leverage the Aurelia Store plugin in your Aurelia applications.

I have been writing on and off for a while and the book now has enough content in it, that I am ready to announce the book. The book is just over 40% complete and keeping in line with how LeanPub operates, the book is a constant work in progress that will be published often. At present, I am publishing once per day.

This means you are buying a work in progress book, but I can tell you the information in it right now will help you if you’re looking to learn how to integrate Aurelia Store into your Aurelia applications as well as work with the underlying RxJS functionality of the store itself.

The book includes many working demos and source code already, and future chapters will equally have a tonne of demos and source code. I am the kind of developer who learns faster with example code, and I know many are the same.

If you have ever been curious how you go about implementing state management into an Aurelia application, or maybe have tried using existing solutions like Redux or MobX and found them intimidating, Aurelia Store is for you.

Buy the book here on LeanPub and pay what you want.