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.

How To Build Complex, Large-scale Aurelia Apps With Aurelia Store

If you’re new to state management or you’re familiar with it and not using Aurelia Store already (you should), today we are going to be looking at how you can integrate Aurelia Store into your Aurelia applications and make the life of your development team and yourself a lot less stressful.

A lot of state management articles will wheel out the TV and VCR player on the tray table with wheels and default to the cliche shopping cart or todo application example to show you how to work with state management.

Look, they’re great simple examples showing you how to work with state management, but they are quite far removed from a large-scale application which could be comprised of hundreds of actions and troves of data going to and from the server.

Unless you’re building a todo application or basic shopping cart, these examples are not going to answer all of your questions nor reflect a real application with a real team working on it.

The truth of the matter is, real-world applications (especially for large products) can get big. I worked on an Aurelia application that had upwards of 40 components, not-to-mention value converters, attribute. a stack load of modals, routed sections and an impressive amount of singleton classes.

What problems does state management solve, and do I even need it?

State management isn’t something you always need, but if you’re working with a growing collection of data (from an API or user-entered) and you’re sharing it across your application, state management is unavoidable or you’ll end up with singleton soup.

For a long time using Aurelia, I actually avoided using state management, even though other solutions predate Aurelia Store such as MobX and Redux. The problem that most other state management solutions share is they require serious “buy in” to use them, they have a cost.

Fortunately, Aurelia Store aligns well with the Aurelia mantra of “just write code” so it doesn’t strictly enforce a specific way of working other than the basics like not directly mutating state and registering actions.

The biggest problem state management addresses in Javascript is: assign by reference. Every variable and value you reference is passed by reference, meaning it can be overwritten or accessed from anywhere in your application without any kind of visible trail which can be disastrous.

When you opt-in to state management, you’re explicitly choosing to update and read data from a centralised store via an abstraction. Good state management prevents you from accidentally overriding a value in the store without leaving a trail (still possible, but more difficult).

One example of where state management shines is Aurelia’s binding system. Picture this scenario, you have a form with 4 inputs and those inputs are using value.bind referencing properties on some object or class. When those values update, the object values also update, form input value bindings are two-way by default.

Now, imagine that object is being shared across your app and you have an array of users. The form allows you to update a user and everywhere sees the change immediately (pass by reference). Now imagine an invalid value is entered or something breaks, how do you revert it? You can’t (unless you have a copy of the object).

If you want to know when the value was updated, how do you do that? In Aurelia, you’ll need to use the propertyObserver API or simplify your app and use @observable to observe changes to values and act accordingly. It results in a lot of additional and potentially performance draining code that becomes a maintenance nightmare over time.

Aurelia Store features

  • A reactive subscription observation system, so when changes are made to the store you can subscribe to the state itself and get the updated changes anywhere in your application. Think when a user logs in and out when a collection of products is loaded.
  • State is not directly mutated, actions are used to update the state and leave a history you can inspect using Redux Dev Tools as well as undo or replay.
  • Supports middleware. Allows you to integrate code that runs at various points of the state lifecycle, allowing you to filter values or check permissions.
  • Aurelia Store gives you a clearer view of your data structures and separates the data layer from the view and view-models (easier to test, easier to refactor).
  • Allows you to have safe and fast cross-component communication, meaning you no longer need to abuse the Event Aggregator or Router to pass data around.
  • Easy to debug using the Redux Dev Tools which the plugin completely supports. A browser plugin for visually seeing actions and state as it happens, as well as call actions.
  • Supports caching out-of-the-box, allows you to cache your data in localStorage and create offline/poor internet connection capable applications.

Structuring an Aurelia app for Aurelia Store

Unlike existing state management solutions, Aurelia Store doesn’t require you to structure your application in a specific way. This is both good and bad because it means you can choose a structure and go down a particular path only to find you chose the wrong architect.

Below is the approach I take in my Aurelia applications using a store, I will create a folder called store in my src directory.

Please keep in mind that I use TypeScript, so the below examples and explanations will be written in TypeScript and vanilla Javascript differs slightly.

src
├── app.html
├── app.ts
├── ...
├── store
│   ├── actions
│   │   ├── auth.ts
│   │   ├── user.ts
│   ├── store.ts
│   ├── state.ts
└── ...

The actions folder contains files which contain functions (actions) that are exported and can be imported where needed. The auth.ts example might have a login and logout method setting and unsetting the currently authentication user.

The user.ts might have actions related to the user like getting content specific to their account, getting an avatar or updating their profile.

The store.ts file is interesting because I actually import the Store itself and get a reference to it via the Aurelia Dependency Injection container. Here is what the inside of my store.ts in new Aurelia applications I build looks like these days:

import { Container } from 'aurelia-framework';
import { Store } from 'aurelia-store';
import { State } from './state';

const store: Store<State> = Container.instance.get(Store);

export default store;

The reason I do this is so I do not have to follow the official examples where the Store is injected into every view-model you want to register actions from within. It was tedious and I wanted an easier way. It also allows me to actually register actions from within the action files themselves instead of view-models, which makes more sense to me.

If you want to manually inject the store into your view-models when needed, the official documentation and examples encourage this approach. This is just another option.

The state.ts file has an object which is the application state structure itself. A basic application using the above example of a structure might look like this:

export interface State {
    auth: {
        loggedIn: boolean;
        token: string;
        refreshToken: string;
    };

    user: {
        id: string;
        username: string;
        avatar: string;
        profileFields: any;
    };
}

export const initialState: State = {
    auth: {
        loggedIn: false,
        token: '',
        refreshToken: ''
    },
    user: {
        id: '',
        username: '',
        avatar: '',
        profileFields: {}
    }
};

Configuring the plugin

We now have the state configured, so you’ll want to pass it as an argument to the aurelia-store plugin registration inside of your main.ts file inside of the exported configure method.

import { Aurelia } from 'aurelia-framework'
import { initialState } from './store/state'; // exported initialState object

export function configure(aurelia: Aurelia) {
  aurelia.use
    .standardConfiguration()
    .feature('resources');

  ...

  aurelia.use.plugin('aurelia-store', { initialState });

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

And now we get into the actions themselves…

We glimpsed over actions earlier because to write them you really need your state in place first. Actions are what mutate the state values and you can actually do quite a lot with them. On a basic level, the first argument is the state object itself and you can pass parameters (which are subsequent arguments).

Actions can be sync or async. This means you can do things like make API requests from within actions and make your application asynchronously call and wait for the returned promise to resolve or reject. Let’s look at our fictitious auth.ts actions file.

import store from 'store/store';
import { State } from 'store/state';

export function login(state: State, token: string, refreshToken: string) {
    const newState = Object.assign({}, state);

    newState.auth.loggedIn = true;
    newState.auth.token = token;
    newState.auth.refreshToken = refreshToken;

    return newState;
}

export function logout(state: State) {
    const newState = Object.assign({}, state);

    newState.auth.loggedIn = false;
    newState.auth.token = '';
    newState.auth.refreshToken = '';

    return newState;
}

store.registerAction('login', login);
store.registerAction('logout', logout);

If you have already read the Aurelia Store documentation (and you should), then you would know that actions should NEVER mutate the passed in state property directly and should always be shallow cloned using something like Object.assign or the spread operator { ...state } to make a copy of it.

You will also notice our login action takes the state like all actions do, but has two other arguments for the token and refreshToken. When the action is dispatched, these can be passed which I’ll show you next.

Actions should always return a copy of the state, which then does the work of update the state object itself. Never just assigning new properties to state, because otherwise, you encounter the pass by reference issue we talked about earlier which is bad as there will be no trail of your updates (hard for testing and debugging).

Similarly, the users.ts actions file might have an async function in it…

import store from 'store/store';
import { State } from 'store/state';

// A fictitious API service you might have
import { Api } from 'services/api';

// Use Aurelia DI to get the api because we are not inside of a view-model
const api: Api = Container.instance.get(Api);

export async function getAvatar(state: State) {
    const newState = Object.assign({}, state);

    try {
        // An API function that accepts the current user ID
        // notice we reference the user object to get the ID?
        const avatarImage = await api.fetchUserAvatar(newState.user.id);

        // Store the avatar
        newState.user.avatar = avatarImage;
    } catch (e) {
        console.error(e);
    }

    return newState;
}

store.registerAction('getAvatar', getAvatar);

Triggering actions

We now have our store setup and configured. Now picture you have a login page with basic username and email fields, you hit a login button and it goes off to the server.

import { autoinject } from 'aurelia-dependency-injection';
import { dispatchify, Store } from 'aurelia-store';

import { State } from 'store/state';

import { login } from 'store/actions/auth';

@autoinject()
export class Login {
    public state: State;
    private subscription: Subscription;

    constructor(private store: Store<State>) { }

    bind() {
        this.subscription = this.store.state.subscribe((state) => this.state = state);
    }

    unbind() {
        this.subscription.unsubscribe();
    }

    doLogin() {
        api.login(username, password)
            .then(result => result.json())
            .then(auth => {
                dispatchify(login)(auth.token, auth.refreshToken);
            });
    }
}

I am using the dispatchify method so I don’t have to manually inject the store into the view-model itself and dispatch the function that way. Worth acknowledging is when you dispatch a function, you pass the function itself and not the name.

The dispatchify method returns a function which is the action itself, which allows you to pass values to its arguments. In our case, we are mocking a login method that calls an API and then if successful, will store the token and refreshToken values.

Async/await actions

We showcased a pretty basic example of dispatching the login action to set the token and refreshToken in the state. Now, let’s showcase how powerful asynchronous actions are, by calling our get user avatar action.

I have been asked this on a few occasions by people interested in the Aurelia Store plugin: is it okay to make API requests and request data from within actions? Absolutely. The fact actions support returning promises makes them the ideal candidate for encapsulating everything related to your data.

You will notice the code looks very much the same as the example above.

import { autoinject } from 'aurelia-dependency-injection';
import { dispatchify, Store } from 'aurelia-store';

import { State } from 'store/state';

import { login } from 'store/actions/user';

@autoinject()
export class User {
    public state: State;
    private subscription: Subscription;

    constructor(private store: Store<State>) { }

    bind() {
        this.subscription = this.store.state.subscribe((state) => this.state = state);
    }

    unbind() {
        this.subscription.unsubscribe();
    }

    async activate() {
        await dispatchify(getAvatar)();

        // If successful, the avatar will be available on this.state.user.avatar
        // which can then be referenced in the view
    }
}

Using getters and computedFrom for sanity

Eventually, you will realise that in your views your referenced state objects and values can be pretty daunting to look at as well as type. You can use computed getters to create shortcuts to values in your store.

Using the above login example, we’ll create a getter to simplify accessing the auth property in our state.

import { autoinject } from 'aurelia-dependency-injection';
import { computedFrom } from 'aurelia-framework'; 
import { dispatchify, Store } from 'aurelia-store';

import { State } from 'store/state';

import { login } from 'store/actions/auth';

@autoinject()
export class Login {
    public state: State;
    private subscription: Subscription;

    constructor(private store: Store<State>) { }

    bind() {
        this.subscription = this.store.state.subscribe((state) => this.state = state);
    }

    unbind() {
        this.subscription.unsubscribe();
    }

        @computedFrom('state.auth') {
            // Allows you to use auth.loggedIn and so on in your views
            return this.state.auth;
        }

    doLogin() {
        api.login(username, password)
            .then(result => result.json())
            .then(auth => {
                dispatchify(login)(auth.token, auth.refreshToken);
            });
    }
}

My approach differs from the official documentation

It is worth pointing out that my approach differs greatly from the official Aurelia Store documentation and examples in the GitHub repository. I am not saying that this is the way you should do it, I am just showing you how I do it and what works for me.

The approach you see above is the same approach I take for all new Aurelia projects using the store. It allows me to neatly organise my actions into bite-sized modules and it just feels very clean.

This is only the start

We didn’t get too in-depth into how you can use the Aurelia Store plugin, because the official documentation does a great job of that already, which you can read here and if you haven’t, I highly recommend you should.

In a separate future article, I will show you how to use Aurelia Store with server-side rendering and implement features such as default state and offline capability.

Aurelia Tips & Tricks

If you are new to Aurelia or perhaps already building something with it, here are some tips and tricks I have learned over the last two years which have helped me write well-performing Aurelia applications.

Keep in mind that Aurelia is like any other framework or library and that it is very easy to write poor performing applications if you’re not careful. Never assume that a framework will stop you from writing bad code.

If vs Show Bindings

In Aurelia there are two attributes: if and show which are similar to one another, but have some fundamental differences. The if binding will add or remove elements from the DOM, whereas the show binding just applies a conditional display:none to whatever element the attribute is used on.

Understandably, for some it is confusing. Do you use if or do you use show? My rule of thumb is defined by how often I am going to show or hide something in my application.

Am I going to show or hide an element in the page regularly or am I conditionally going to show or hide something sporadically or only just once?

The upside of the if binding is when the bound value is false, the elements in the DOM will be removed (freeing up DOM space and bindings will be removed). The downside being Aurelia needs to set up a new controller instance and bindings (which isn’t that big of a deal).

I am a huge fan of a light DOM, so I use if.bind extensively because a large DOM is a lot slower than the time it takes for Aurelia to setup controller instances and bindings. Both have a purpose, it is important to use what works for you.

I do find if.bind works well for me in most cases, no point having elements around if they’re not being used (in my opinion).

Avoid dirty-checking at all costs

If you’re not sure what dirty-checking is, essentially it’s a timer with a 120-millisecond timeout value that repeatedly loops and checks for changes. You definitely do not want dirty-checking in your application (unless you absolutely need it for some edge case).

If you define a getter in your view-model which accesses one or more values in your class and you do not supply the computedFrom decorator, it will be dirty-checked.

An example of dirty-checking can be seen below:

export class MyClass {
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
}

<template>
    <h1>${fullName}</h1>
</template>

Internally, Aurelia is going to dirty-check this using a setInterval to constantly poll if the value changes, this is bad. Fortunately, using computedFrom we can make this an optimised getter which only reacts when one or more dependencies change.

The below example does not use a timer to poll for changes, it makes the getter reactive.

import {computedFrom} from 'aurelia-framework';

export class MyClass {
    @computedFrom('firstName', 'lastName')
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
}

<template>
    <h1>${fullName}</h1>
</template>

A note on computedFrom: the this part is implied, so when supply one or more computed values to computedFrom you are automatically referencing the current class and do not need to supply this.

A note on computed arrays

the computedFrom decorator is great for telling Aurelia about your getter dependencies, but it doesn’t work for all values. One such situation is arrays, an array cannot be directly supplied as a getter computed value because it won’t update.

If you’re looking to force a getter to update when an array changes, computed based on its length. When the size of the array changes (items are added or removed) the getter will fire.

import {computedFrom} from 'aurelia-framework';

export class MyClass {
    @computedFrom('arr.length')
    get firstValue() {
        return `${this.arr[0]}`;
    }
}

<template>
    <h1>${firstValue}</h1>
</template>

Think big by thinking small

If you come from an MVC background, then you’ve heard the expression, “fat model, skinny controller” and other countless expressions around MVC architecture which have sort-of been carried over into the front-end development jungle.

I prefer fat nothing in my Aurelia applications (or web applications full-stop). If your view-models and/or views are massive, then you have a code architecture problem which is easily solved by reusable components.

A large view-model or view is eventually going to be your undoing (besides the annoying Git conflicts you will encounter working in a team on large files). Large files which do too much are counterproductive and unnecessarily complicated.

If you want to ensure your application is easy to build upon and make it easier for the browser, build tools and test runners to work with your code: break things up into reusable components.

I highly recommend approaching the architecture of your Aurelia applications using the Single responsibility principle.

Use view-cache

This isn’t documented very well, but Aurelia provides a view-cache which can allow you to cache heavy views. This means if you have quite a complex view and you navigate away, but come back to it later Aurelia will use the view-cache and update all of the appropriate bindings.

The benefits are obvious: the whole view doesn’t need to be recreated when you navigate back to it. Just throw view-cache onto the main opening <template view-cache="*"> tag, which also accepts a cache size value.

If you supply an asterisk * to view-cache it will cache all instances or if you supply a numeric value, cache the number supplied.

Use compose when nothing else fits

Aurelia provides a <compose> custom element which allows you to dynamically compose from within your application. You can dynamically compose view-models, views and pass in data as well.

As great as <compose> is, I try and avoid it wherever I possibly can. It’s not that I think <compose> is bad, it’s the fact that <compose> is an abstraction and where possibly, I try and avoid abstractions in my applications.

I have experienced instances where <compose> has made debugging more difficult than straight-up view-models and components.

Assess your needs and if <compose> is the only option, then by all means use it.

Use Binding Behaviors

Out-of-the-box, Aurelia ships with some great binding behaviours which allow you to make bindings in your applications more efficient and performant.

A binding behaviour in your view templates is denoted by an ampersand “&” and much like value converters, they can be chained and have parameters which accept values.

throttle

A rate-limiting throttling behaviour which allows you to throttle the rate in which the view-model is notified of a change in a two-way binding situation. By default the throttle value is 200ms.

debounce

Very similar to the throttle binding behaviour, the debounce behaviour will prevent a binding from being updated until the debounce interval completes after no changes have been made.

updateTrigger

Allows you to specify which input events signal to Aurelia’s binding system that a change has been made. By default, the events that trigger a change are change and input.

signal

Allows you to tell Aurelia’s binding system to refresh a binding. It works like an event listener on a binding and when you fire an update signal, it refreshes the binding which works similarly to how a first-page load does.

oneTime

Use the oneTime binding behaviour as much as possible. It allows you to tell Aurelia’s binding system to display a binding value and then forget it. A one-time binding will not update if the value changes, which can lead to great application performance.

If you would like to see examples of binding behaviours and how to work with them, Aurelia core team member has a great write-up on working with binding behaviours here which I recommend you also read.

Batch DOM changes using the Task Queue

The Aurelia Task Queue is a powerful module that allows you to sort of hook into the browsers event loop which allows you to perform DOM actions in an efficient way.

While slow Javascript code can definitely affect performance, it is a known fact that the DOM is the bottleneck of any web application, which is why libraries like React and Vue leverage a virtual DOM. Working with the DOM inefficiently can result in poor browser performance.

By queuing up a microtask, we can batch changes in the page resulting in less reflow and repaints.

import {TaskQueue} from 'aurelia-task-queue'; 

export class MyViewModel {
    static inject = [TaskQueue];

    constructor(taskQueue) {
        this.taskQueue = taskQueue;
    }

    attached() {
        this.makeSomeChanges();
    }

    makeSomeChanges() {
        this.taskQueue.queueMicroTask(() => {
            const header = document.getElementById('header');

            // Dynamically set the width and height of an element with ID "header"
            // We are batching DOM changes, so we only get on repaint/reflow
            header.style.height = '250px';
            header.style.width = '500px';
        });
    }
}

Be smart about event handling

In Aurelia, there are two ways to create event listeners. You can create an event listener the Javascript way using addEventListener or you can also bind to events from within your views with one such example being click.delegate="myCallback()".

Where possible, you should use Aurelia’s templating for binding to events. The biggest advantage being Aurelia cleans up after itself and removes events when they’re no longer being used.

This is not to say that addEventListener is completely redundant, but for eventing around elements in your page, you can and should use Aurelia’s provided way of working with native events.

You’ll have the piece of mind that events are properly being unbound when views are being destroyed, it’s like programming languages that automatically manage memory for you like PHP.

Don’t abuse the Event Aggregator

Aurelia comes with a great Event Aggregator module which allows you to publish and subscribe to events from within your application. The routing module also uses the Event Aggregator, firing off various events at different stages of the routing process.

As great as the Event Aggregator is, I have seen it abused quite a lot. I have done a bit of Aurelia consulting and in most instances, the Event Aggregator is being used for things it shouldn’t be used for.

The biggest issue you will encounter with the Event Aggregator is that it is hard to debug. This rings true for most custom eventing, not just Aurelia’s module.

So, when are you supposed to use the Event Aggregator then?

Do’s

  • Use the Event Aggregator to notify parts of your application about specific actions; user added, recorded deleted, a user logged in, a user logged out, etc.
  • Use the Event Aggregator to react to specific actions; a modal opening or closing, a user is deleted or if the user logs out clearing out a token in localStorage, etc.

Do nots

  • Don’t use the Event Aggregator for passing data between routes
  • Don’t use the Event Aggregator for passing data between components
  • Never treat the Event Aggregator as a crucial dependency (creating components that rely on specific events and values)

Passing data between routes

A common scenario I have witnessed in the community is wanting to route from Route A to route B and pass some data to the route you are navigating too.

I’ve seen developers pass data using the Event Aggregator (see above, don’t do that), use localStorage (also, don’t do that) and the even crazier: storing it on the route object itself (seriously, don’t do that).

The way that I always recommend passing data between routes and components is by using a singleton class. If you come from an Angular background, then you might know this as a service class.

Assuming you have two routes: Route A and Route B, and in Route A the user can enter their name and then be navigated to RouteB which will display their name.

I would achieve this in the following way:

    import {AppService} from './app-service';

    export class RouteA {
        static inject = [AppService];

        constructor(appService) {
            this.appService = appService;
        }
    }

    <template>
        <h1>Welcome: Route A</h1>
        <label>Please enter your name: <input type="text" value.bind="appService.name"></label>
    </template>

    import {AppService} from './app-service';

    export class RouteB {
        static inject = [AppService];

        constructor(appService) {
            this.appService = appService;
        }
    }

    <template>
        <h1>Hello, ${appService.name}</h1>
        Welcome to RouteB. The name you provided on the previous page is displayed above.
    </template>

    // Assuming this file is saved as app-service.js alongside the other route view-models
    export class AppService {
        constructor() {
            this.name = '';
        }
    }

Or better still, use a state management solution if your application state is complex and requires a much more manageable solution. The Aurelia Store is my favourite and recommended state management solution for Aurelia applications.