Google News
logo
Aurelia Interview Questions
Aurelia is a collection of Modern JavaScript modules, which when used together, function as a powerful platform for building browser, desktop and mobile applications, all open source and built on open web standards.
 
Aurelia is a client side JavaScript framework with an emphasis on simple conventions and ES6/ES7 support. The ES6/ES7 support is transpired for you so it’s compatible with today’s browsers.

Aurelia is free and its code is open sourced under the MIT License , a very permissive license used by many popular web projects today. Its starter kits and documentation are available under the Creative Commons 0 license. 
Rather than being a monolithic framework, Aurelia is broken down into a collection of feature-oriented modules. Examples of feature modules include metadata, dependency injection, binding, templating, router and more. Each module is written using ECMAScript (aka JavaScript) or TypeScript (a strict superset of JavaScript that adds compile-time type checking). Many of these modules can be used individually in any type of JavaScript project, including Node.js.
There are many frameworks to choose from today. We believe that Aurelia provides a fresh and exciting approach to front-end development with power and flexibility that is unmatched by other options. That said, we recognize that each team and each project has different needs. You might find Aurelia to be the right choice for you if...
 
You want an all-in-one solution : Aurelia provides core capabilities like dependency injection, templating, routing and pub/sub, so you don't have to piece together a bunch of libraries in order to build an application. On top of this rich core, Aurelia also provides a number of additional plugins for internationalization, validation, modal dialogs, UI virtualization and much more. You also don't have to cobble together a bunch of different tools. Aurelia provides a CLI for generating and building projects, a browser plugin for debugging and a VS Code plugin as well. Yet, you're not forced to use any of these as Aurelia is structured to enable you to swap out any detail, even down to the templating/binding engine, in order to guarantee maximum flexibility.

You need blazing rendering speed and great memory efficiency : In 3rd-party benchmarks like DB Monster, Aurelia renders faster than any other framework today. Because of its batched rendering and observable object pooling, Aurelia also utilizes less memory and causes less GC churn than other frameworks.

You require the safety of uni-directional data-flow, but need the productivity of data-binding : Aurelia features an observable-based binding system that uses uni-directional data-flow by default, pushing data from your model into your view via a highly efficient, DOM-batching mechanism. Two-way binding can also be leveraged for HTML form controls, allowing for increased developer productivity, without sacrificing the safety of uni-directional flow or that of component encapsulation.

You desire API stability amidst a turbulent JavaScript landscape : Aurelia follows Semver and works hard not to make breaking changes to its APIs. We're proud to say that we've continued to innovate and advance the platform while having no breaking changes to core framework APIs since our 1.0 release on July 27, 2016.
You value high standards compliance - Focused on ES2015+ and W3C Web Components while avoiding unnecessary abstractions, Aurelia provides the cleanest and most standards-compliant component model you'll find anywhere.

You think a framework should "get out of your way" : Aurelia is the only framework that lets you build components with plain, vanilla JavaScript/TypeScript. The framework stays out of your way so your code remains clean and easy to evolve over time.

You like programming models that are easy to learn and remember : Because of its simple, consistent design, developers are able to learn a very small set of Aurelia patterns and APIs while unlocking limitless possibilities. Simple conventions help developers follow solid patterns and reduce the amount of code they have to write and maintain. This all results in less fiddling with the framework and more focus on the application.

You prefer a platform that integrates well with other frameworks and libraries : Because of the extensible design of Aurelia and its strict adherence to web standards, it's easy to integrate Aurelia with any 3rd party library or framework, including jQuery, React, Polymer, Bootstrap, MaterializeCSS and many more.

You love or want to be a part of open source : Aurelia is open sourced under the MIT license and doesn't add or remove special clauses or conditions to the license. We're proud of the work our community has done together and we'd love you to join in and help us make Aurelia better for everyone.

You thrive on being part of a welcoming community : With one of the largest and most active developer gitter channels, a huge number of contributors and a large, active core team, Aurelia has an amazing community. Our core team and community love to welcome new developers and we all work hard to help each other succeed.
Modern JavaScript : 
* Fully written in standards-based ES2015+ and TypeScript.
* Forward compatible with JavaScript technology coming in future ECMAScript specs.
* Full support for both Babel and TypeScript.

Modern DOM :
* Consistently leverages the most modern DOM APIs.
* Bare "to the metal" usage of the DOM; no DOM wrappers in order to ensure maximum performance and memory efficiency.
* Automatically polyfills the DOM where appropriate, in order to support older browsers.

Modern Tooling :
* Supports modern build tooling via the Aurelia CLI and Webpack, out-of-the-box.
* Works well with powerful testing tools like Karma and Protractor.
* Provides a custom Chrome debug panel as well as a VS Code plugin.

Code Quality :
* Source code is covered by an extensive suite of unit tests.
* All source is fully linted for style and feature-usage consistency throughout.
* TypeScript d.ts files and full API documentation are provided for all libraries.

Web Component Standards :
* Leverages W3C Web Components specs such as HTMLTemplateElement and ShadowDOM.
* Fully compatible with 3rd-party Web Components, even those originating from other frameworks, such as Polymer.
* Provides a Web Component-based programming model even on browsers that will never support Web Components.

Modularity :
* Highly modular development, suitable for small and large-scale apps alike.
* Native support for feature-based development facilitating parallel development of multiple teams on the same app.
* Strong component model for high re-use of UI components across apps.

Platform Support :
* Designed for modern web browsers but supports older browsers, such as IE9, via additional polyfills.
* Designed for mobile application development in combination with PhoneGap/Cordova/Crosswalk.
* Designed for desktop application development in combination with Electron or NWJS.
* Write apps in ES2015+ and TypeScript.
* One simple way of creating components that work in a variety of contexts:
* Custom Elements
* Dynamically Composed UI (data-driven component composition)
* Routing/Navigation
* Modal Dialogs
* Web Components
* Progressive Enhancement
* Custom scenarios enabled through low-level access to our View Composition Engine
* Fully-extensible View Compiler, View Engine and View Resource Pipeline.
* Fully-extensible and adaptive data-binding engine.
* Powerful and flexible hierarchical dependency injection.
* Eager/Lazy/Hybrid loading of any/all application resources.
* Powerful application router with support for encapsulated child routers for multi-team, large-scale development.
* Optionally create standards-compliant Web Components or use Aurelia to "shield" you from unstable specs.
* Interoperate with any standards-compliant Web Component.
* Loosely coupled cross-component communication via publish/subscribe.
* Fully customizable application startup and plugin model.
* Enables authoring of testable, maintainable and extensible code.
* Leverage conventions to write less code and get more done.
* Little to no framework intrusion, so developers can focus on their app, not the framework.
* Application and package bundling compatible with all major build systems.
Most platforms have a "main" or entry point for code execution. Aurelia is no different. If you've read the Quick Start, then you've seen the aurelia-app attribute. Simply place this on an HTML element and Aurelia's bootstrapper will load an app.js and app.html, databind them together and inject them into the DOM element on which you placed that attribute.
 
Standard Configuration : ES Next
export function configure(aurelia) {
    aurelia.use
      .standardConfiguration()
      .developmentLogging();
  
    aurelia.start().then(() => aurelia.setRoot());
  }​
 
Standard Configuration : TypeScript
import {Aurelia} from 'aurelia-framework';
  
  export function configure(aurelia: Aurelia): void {
    aurelia.use
      .standardConfiguration()
      .developmentLogging();
  
    aurelia.start().then(() => aurelia.setRoot());
  }
 
 
So, if you want to keep all the default settings, it's really easy. Just call standardConfiguration() to configure the standard set of plugins. Then call developmentLogging() to turn on logging in debug mode, output to the console.
 
The use property on the aurelia instance is an instance of FrameworkConfiguration. It has many helper methods for configuring Aurelia. For example, if you wanted to manually configure all the standard plugins without using the standardConfiguration() helper method to do so and you wanted to configure logging without using the helper method for that, this is how you would utilize the FrameworkConfiguration instance:
 
Manual Configuration : ES Next
  import {LogManager} from 'aurelia-framework';
  import {ConsoleAppender} from 'aurelia-logging-console';
  
  LogManager.addAppender(new ConsoleAppender());
  LogManager.setLevel(LogManager.logLevel.debug);
  
  export function configure(aurelia) {
    aurelia.use
      .defaultBindingLanguage()
      .defaultResources()
      .history()
      .router()
      .eventAggregator();
  
    aurelia.start().then(() => aurelia.setRoot());
  }
 
Manaual Configuration : TypeScript
import {Aurelia, LogManager} from 'aurelia-framework';
  import {ConsoleAppender} from 'aurelia-logging-console';
  
  LogManager.addAppender(new ConsoleAppender());
  LogManager.setLevel(LogManager.logLevel.debug);
  
  export function configure(aurelia: Aurelia): void {
    aurelia.use
      .defaultBindingLanguage()
      .defaultResources()
      .history()
      .router()
      .eventAggregator();
  
    aurelia.start().then(() => aurelia.setRoot());
  }​
Similar to features, you can install 3rd party plugins. The main difference is that a "feature" is provided internally by your application, while a plugin is installed from a 3rd party source through your package manager.
 
To use a plugin, you first install the package. For example jspm install my-plugin would use jspm to install the my-plugin package. Once the package is installed, you must configure it in your application. Here's some code that shows how that works.
 
Using a Plugin : ES Next
export function configure(aurelia) {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .plugin('my-plugin', pluginConfiguration);
  
    aurelia.start().then(() => aurelia.setRoot());
  }
 
Using a Plugin : TypeScript
import {Aurelia} from 'aurelia-framework';
  
  export function configure(aurelia: Aurelia): void {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .plugin('my-plugin', pluginConfiguration);
  
    aurelia.start().then(() => aurelia.setRoot());
  }
  
Simply provide the same name used during installation to the plugin API. Some plugins may require configuration (see the plugin's documentation for details). If so, pass the configuration object or configuration callback function as the second parameter of the plugin API.
 
While all plugins work in a similar manner, consider the real-world example of adding and configuring the dialog plugin by using a configuration callback. The configuration parameter in this case is a type of DialogConfiguration and the above code would become:
 
Using a Plugin : ES Next
export function configure(aurelia) {s
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .plugin('aurelia-dialog', config => {
        config.useDefaults();
        config.settings.lock = true;
        config.settings.centerHorizontalOnly = false;
        config.settings.startingZIndex = 5;
        config.settings.keyboard = true;
      });
  
    aurelia.start().then(() => aurelia.setRoot());
  }
 
Using a Plugin : TypeScript
export function configure(aurelia: Aurelia): void {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .plugin('aurelia-dialog', config => {
        config.useDefaults();
        config.settings.lock = true;
        config.settings.centerHorizontalOnly = false;
        config.settings.startingZIndex = 5;
        config.settings.keyboard = true;
      });
  
      aurelia.start().then(() => aurelia.setRoot());
    }
Logging : Aurelia has a simple logging abstraction that the framework itself uses. By default it is a no-op. The configuration in the above examples shows how to install an appender which will take the log data and output it to the console. Here's the code again, for convenience :
 
Configuring Logging : ES Next
import {LogManager} from 'aurelia-framework';
  import {ConsoleAppender} from 'aurelia-logging-console';
  
  LogManager.addAppender(new ConsoleAppender());
  LogManager.setLevel(LogManager.logLevel.debug);
  
  export function configure(aurelia) {
    aurelia.use
      .standardConfiguration;
  
    aurelia.start().then(() => aurelia.setRoot());
  }
 
Configuring Logging : TypeScript
import {LogManager, Aurelia} from 'aurelia-framework';
  import {ConsoleAppender} from 'aurelia-logging-console';
  
  LogManager.addAppender(new ConsoleAppender());
  LogManager.setLevel(LogManager.logLevel.debug);
  
  export function configure(aurelia: Aurelia): void {
    aurelia.use
      .standardConfiguration;
  
    aurelia.start().then(() => aurelia.setRoot());
  }
You can also see how to set the log level. Values for the logLevel include : none, error, warn, info and debug.
To create a UI component, you need only create two files, one for each of the component parts. Let's create a simple "Hello" component. To do that we'll need a hello.js for our view-model and hello.html for our view. Here's the source for each :
 
hello.js : ES Next
export class Hello {
    constructor() {
      this.firstName = 'John';
      this.lastName = 'Doe';
    }
  
    sayHello() {
      alert(`Hello ${this.firstName} ${this.lastName}. Nice to meet you.`);
    }
  }
 
hello.ts : TypeScript
export class Hello {
    firstName: string = 'John';
    lastName: string = 'Doe';
  
    sayHello() {
      alert(`Hello ${this.firstName} ${this.lastName}. Nice to meet you.`);
    }
}
hello.html
<template>
    <input value.bind="firstName">
    <input value.bind="lastName">
  
    <button click.trigger="sayHello()">Say Hello</button>
</template>
All components have a well-defined lifecycle. Below is a list of methods you can implement on your view-model in order to hook into the component lifecycle:
 
constructor() : The view-model's constructor is called first.

created(owningView: View, myView: View) : If the view-model implements the created callback it is invoked next. At this point in time, the view has also been created and both the view-model and the view are connected to their controller. The created callback will receive the instance of the "owningView". This is the view that the component is declared inside of. If the component itself has a view, this will be passed second.

bind(bindingContext: Object, overrideContext: Object) : Databinding is then activated on the view and view-model. If the view-model has a bind callback, it will be invoked at this time. The "binding context" to which the component is being bound will be passed first. An "override context" will be passed second. The override context contains information used to traverse the parent hierarchy and can also be used to add any contextual properties that the component wants to add.

attached() : Next, the component is attached to the DOM (in document). If the view-model has an attached callback, it will be invoked at this time.

detached() : If defined on your view-model - is invoked after the component has been removed from the DOM. Due to navigating away or other reasons.

unbind() : After a component is detached, it's usually unbound. If your view-model has the unbind callback, it will be invoked during this process.

Each of these callbacks is optional. Implement whatever makes sense for your component, but don't feel obligated to implement any of them if they aren't needed for your scenario. Usually, if you implement bind you will need to implement unbind. The same goes for attached and detached, but again, it isn't mandatory.
A dependency injection container is a tool that can simplify the process of decomposing such a system. Often times, when developers go through the work of destructuring a system, they introduce a new complexity of "re-assembling" the smaller parts again at runtime. This is what a dependency injection container can do for you, using simple declarative hints.
 
Injection : Let's say we have a CustomerEditScreen that needs to load a Customer entity by ID from a web service. We wouldn't want to place all the details of our AJAX implementation inside our CustomerEditScreen class. Instead, we would want to factor that into a CustomerService class that our CustomerEditScreen, or any other class, can use when it needs to load a Customer. Aurelia's dependency injection container lets you accomplish this by declaring that the CustomerEditScreen needs to have a CustomerService injected at creation time.
 
CustomerEditScreen Injection : TypeScript
import {CustomerService} from 'backend/customer-service';
  import {inject} from 'aurelia-framework';
  
  @inject(CustomerService)
  export class CustomerEditScreen {
    constructor(private customerService: CustomerService) {
      this.customer = null;
    }
  
    activate(params) {
      return this.customerService.getCustomerById(params.customerId)
        .then(customer => this.customer = customer);
    }
}
Each object created by the dependency injection container has a "lifetime". There are three lifetime behaviors that are typical :
 
Container Singleton : A singleton class, A, is instantiated when it is first needed by the DI container. The container then holds a reference to class A's instance so that even if no other objects reference it, the container will keep it in memory. When any other class needs to inject A, the container will return the exact same instance. Thus, the instance of A has its lifetime connected to the container instance. It will not be garbage collected until the container itself is disposed and no other classes hold a reference to it.

Application Singleton : In Aurelia, it's possible to have child DI containers created from parent containers. Each of these child containers inherits the services of the parent, but can override them with their own registrations. Every application has a root DI container from which all classes and child containers are created. An application singleton is just like a container singleton, except that the instance is referenced by the root DI container in the application. This means that the root and all child containers will return the same singleton instance, provided that a child container doesn't explicitly override it with its own registration.

Transient : Any DI container can create transient instances. These instances are created each time they are needed. The container holds no references to them and always creates a new instance for each request.
Now, imagine that we have a Container named root and we call root.createChild() to create a child container named child. Then, we invoke child.get(A) to resolve an instance of A.

What will happen? First, child checks for a Resolver for A. If none is found, then it calls get(A) on its parent which is the root container from which it was created. root then checks to see if it has a Resolver. If not, it auto-registers A in root and then immediately calls the Resolver to get an instance of A.
Imagine that we have a single instance of Container called root. If a developer (or Aurelia) invokes root.get(A) to resolve an instance of A, the root will first check to see if it has a Resolver for A. If one is found, the Resolver is used to get the instance, which is then returned to the developer. If one is not found, the container will auto-register a Resolver for A. This resolver is configured with a singleton lifetime behavior. Immediately after auto-registration, the Resolver is used to get the instance of A which is returned to the developer. Subsequent calls to root.get(A) will now immediately find a Resolver for A which will return the singleton instance.
Dependency Injection container uses Resolvers internally to provide all instances. When explicitly configuring the container, you are actually specifying what Resolver should be associated with a particular lookup key. However, there's a second way that resolvers are useful. Instead of supplying a key as part of the inject decorator, you can provide a Resolver instead.
 
This resolver then communicates with the container to provide special resolution behavior, specific to the injection. Here's a list of the resolvers you can use in this capacity:
 
Lazy : Injects a function for lazily evaluating the dependency.
Ex. Lazy.of(HttpClient)

All : Injects an array of all services registered with the provided key.
Ex. All.of(Plugin)

Optional : Injects an instance of a class only if it already exists in the container; null otherwise.
Ex. Optional.of(LoggedInUser)

Parent : Skips starting dependency resolution from the current container and instead begins the lookup process on the parent container.
Ex. Parent.of(MyCustomElement)

Factory : Used to allow injecting dependencies, but also passing data to the constructor.
Ex. Factory.of(CustomClass)

NewInstance : Used to inject a new instance of a dependency, without regard for existing instances in the container.
Ex. NewInstance.of(CustomClass).as(Another)
 
If using TypeScript, keep in mind that @autoinject won't allow you to use Resolvers. You also can use inject as argument decorator for your own custom resolvers, eg constructor(@inject(NewInstance.of(HttpClient)) public client: HttpClient){...}. Available build-in function parameter decorators are :
 
* lazy(key)
* all(key)
* optional(checkParent?)
* parent
* factory(key)
* newInstance(asKey?, dynamicDependencies: [any])

Here's an example of how we might express a dependency on HttpClient that we may or may not actually need to use, depending on runtime scenarios :
Using Resolvers : TypeScript
import {lazy} from 'aurelia-framework';
  import {HttpClient} from 'aurelia-fetch-client';
  
  export class CustomerDetail {
    constructor(@lazy(HttpClient) private getHTTP: () => HttpClient){ }
  }
 
In this case, the Lazy resolver doesn't actually provide an instance of HttpClient directly. Instead, it provides a function that can be invoked at some point in the future to obtain an instance of HttpClient if needed.
bind, one-way, two-way & one-time : 

Use on any HTML attribute.
 
* .bind : Uses the default binding. One-way binding for everything but form controls, which use two-way binding.
* .one-way : Flows data one direction: from the view-model to the view.
* .two-way : Flows data both ways: from view-model to view and from view to view-model.
* .one-time : Renders data once, but does not synchronize changes after the initial render.

Data Binding Example :
<template>
    <input type="text" value.bind="firstName">
    <input type="text" value.two-way="lastName">
  
    <a href.one-way="profileUrl">View Profile</a>
</template>
Use on any native or custom DOM event. (Do not include the "on" prefix in the event name.)
 
* .trigger : Attaches an event handler directly to the element. When the event fires, the expression will be invoked.

* .delegate : Attaches a single event handler to the document (or nearest shadow DOM boundary) which handles all events of the specified type, properly dispatching them back to their original targets for invocation of the associated expression.
 
Event Binding Example :
<template>
    <button click.trigger="save()">Save</button>
    <button click.delegate="save($event)">Save</button>
</template>
Basic Route Configuration Example : TypeScript
  import {RouterConfiguration, Router} from 'aurelia-router';
  
  export class App {
    configureRouter(config: RouterConfiguration, router: Router): void {
      this.router = router;
      config.title = 'Aurelia';
      config.map([
        { route: ['', 'home'],       name: 'home',       moduleId: 'home/index' },
        { route: 'users',            name: 'users',      moduleId: 'users/index',   nav: true },
        { route: 'users/:id/detail', name: 'userDetail', moduleId: 'users/detail' },
        { route: 'files*path',       name: 'files',      moduleId: 'files/index',   href:'#files',   nav: true }
      ]);
    }
  }
Route Pattern Options :

static routes 
  * ie 'home' : Matches the string exactly.
parameterized routes
  * ie 'users/:id/detail' : Matches the string and then parses an id parameter. Your view-model's activate callback will be called with an object that has an id property set to the value that was extracted from the url.
wildcard routes
  * ie 'files*path' : Matches the string and then anything that follows it. Your view-model's activate callback will be called with an object that has a path property set to the wildcard's value.
* canActivate(params, routeConfig, navigationInstruction) : Implement this hook if you want to control whether or not your view-model can be navigated to. Return a boolean value, a promise for a boolean value, or a navigation command.

* activate(params, routeConfig, navigationInstruction) : Implement this hook if you want to perform custom logic just before your view-model is displayed. You can optionally return a promise to tell the router to wait to bind and attach the view until after you finish your work.

* canDeactivate() : Implement this hook if you want to control whether or not the router can navigate away from your view-model when moving to a new route. Return a boolean value, a promise for a boolean value, or a navigation command.

* deactivate() : Implement this hook if you want to perform custom logic when your view-model is being navigated away from. You can optionally return a promise to tell the router to wait until after you finish your work.
If you include the aurelia-event-aggregator plugin using "basicConfiguration" or "standardConfiguration" then the singleton EventAggregator's API will be also present on the Aurelia object. You can also create additional instances of the EventAggregator, if needed, and "merge" them into any object. To do this, import includeEventsIn and invoke it with the object you wish to turn into an event aggregator. For example includeEventsIn(myObject). Now my object has publish and subscribe methods and can be used in the same way as the global event aggregator, detailed below.
 
Publishing on a Channel : TypeScript
import {autoinject} from 'aurelia-framework';
  import {EventAggregator} from 'aurelia-event-aggregator';
  
  @autoinject
  export class APublisher {
    constructor(private eventAggregator: EventAggregator) { }
  
    publish(): void {
      var payload = {};
      this.eventAggregator.publish('channel name here', payload);
    }
  }
  
Subscribing to a Channel : TypeScript
import {autoinject} from 'aurelia-framework';
  import {EventAggregator} from 'aurelia-event-aggregator';
  
  @autoinject
  export class ASubscriber {
    constructor(private eventAggregator: EventAggregator) { }
  
    subscribe(): void {
      this.eventAggregator.subscribe('channel name here', payload => {
          ...
      });
    }
  }
Publishing a Message : TypeScript
  //some-message.ts
  export class SomeMessage{ }
  
  //a-publisher.ts
  import {autoinject} from 'aurelia-framework';
  import {EventAggregator} from 'aurelia-event-aggregator';
  import {SomeMessage} from './some-message';
  
  @autoinject
  export class APublisher {
    constructor(private eventAggregator: EventAggregator) { }
  
    publish(): void {
      this.eventAggregator.publish(new SomeMessage());
    }
  }
Subscribing to a Message Type : TypeScript
  import {autoinject} from 'aurelia-framework';
  import {EventAggregator} from 'aurelia-event-aggregator';
  import {SomeMessage} from './some-message';
  
  @autoinject
  export class ASubscriber {
    constructor(private eventAggregator: EventAggregator) { }
  
    subscribe(): void {
      this.eventAggregator.subscribe(SomeMessage, message => {
          ...
      });
    }
  }
Use the ref binding command to create a reference to a DOM element. The ref command's most basic syntax is ref="expression". When the view is data-bound the specified expression will be assigned the DOM element.
  <template>
    <input type="text" ref="nameInput"> ${nameInput.value}
  </template>
The ref command has several qualifiers you can use in conjunction with custom elements and attributes :
 
* element.ref="expression" : create a reference to the DOM element (same as ref="expression").

* attribute-name.ref="expression" : create a reference to a custom attribute's view-model.

* view-model.ref="expression" : create a reference to a custom element's view-model.

* view.ref="expression" : create a reference to a custom element's view instance (not an HTML Element).

* controller.ref="expression" : create a reference to a custom element's controller instance.
String interpolation expressions enable interpolating (surprise!) the result of an expression with text. The best way to demonstrate this capability is with an example. Below are two span elements with data-bound textcontent :
<span textcontent.bind="'Hello' + firstName"></span>
  
<span>Hello ${firstName}</span>
The first span uses the bind command. The second uses string interpolation. The interpolated version is much easier to read and easy to remember because the syntax matches the template literal syntax standardized in ES2015.
 
String interpolation can be used within HTML attributes as an alternative to to-view binding. By default, the mode of an interpolation binding is to-view and the result of the expression is always coerced to a string. Results that are null or undefined will result in an empty string.
The binding system makes several properties available for binding in your templates, depending on the context.
 
* $this : The binding context (the view-model).

* $parent : Explicitly accesses the outer scope from within a compose or repeat template. You may need this when a property on the current scope masks a property on the outer scope. Chainable- eg $parent.$parent.foo is supported.

* $event : The DOM Event in delegate or trigger bindings.

* $index : In a repeat template, the index of the item in the collection.

* $first : In a repeat template, is true if the item is the first item in the array.

* $last : In a repeat template, is true if the item is the last item in the array.

* $even : In a repeat template, is true if the item has an even numbered index.

* $odd : In a repeat template, is true if the item has an odd numbered index.
Class : You can bind an element's class attribute using string interpolation or with .bind/.to-view.
<template>
    <div class="foo ${isActive ? 'active' : ''} bar"></div>
    <div class.bind="isActive ? 'active' : ''"></div>
    <div class.one-time="isActive ? 'active' : ''"></div>
</template>

 

To ensure maximum interoperability with other JavaScript libraries, the binding system will only add or remove classes specified in the binding expression. This ensures classes added by other code (eg via classList.add(...)) are preserved. This "safe by default" behavior comes at a small cost but can be noticeable in benchmarks or other performance critical situations like repeats with lots of elements. You can opt out of the default behavior by binding directly to the element's className property using class-name.bind="...." or class-name.one-time="...". This will be marginally faster but can add up over a lot of bindings.
 
Style : You can bind a css string or object to an element's style attribute. Use css custom attribute when doing string interpolation in your view to ensure your application is compatible with Internet Explorer and Edge. If you don't use interpolation in css - it won't get processed, so if you are just using inline style - use the proper style attribute of HTMLElement.
 
Style Binding Data : TypeScript
  export class StyleData {
    styleString: string;
    styleObject: any;
  
    constructor() {
      this.styleString = 'color: red; background-color: blue';
  
      this.styleObject = {
        color: 'red',
        'background-color': 'blue'
      };
    }
  }
Style Binding Example :
  <template>
    <div style.bind="styleString"></div>
    <div style.bind="styleObject"></div>
  </template>
Sometimes it is desirable to return a dynamically computed value when accessing a property, or you may want to reflect the status of an internal variable without requiring the use of explicit method calls. In JavaScript, this can be accomplished with the use of a getter.
 
Here's an example Person class that exposes a fullName property that computes it's value using the firstName and lastName properties.
 
Computed Properties : TypeScript
  export class Person {
    firstName: string = 'John';
    lastName: string = 'Doe';
  
    get fullName(): string {
      return `${this.firstName} ${this.lastName}`;
    }
  }
  
There isn't anything special you need to do to bind to a computed property like fullName. The binding system will examine the property's descriptor , determine that the value of the property is computed by a function and choose the dirty checking observation strategy. Dirty checking means the binding system will periodically check the property's value for changes and update the view as-needed. This means your property's getter function will be executed many times, approximately once every 120 milliseconds. Most of the time this isn't an issue, however, if you're using a lot of computed properties or if your getter functions are sufficiently complex you may want to consider giving the binding system hints on what to observe so that it doesn't need to use dirty checking. This is where the @computedFrom decorator comes in:
 
Computed Properties : TypeScript
  import {computedFrom} from 'aurelia-framework';
  
  export class Person {
    firstName: string = 'John';
    lastName: string = 'Doe';
  
    @computedFrom('firstName', 'lastName')
    get fullName(): string {
      return `${this.firstName} ${this.lastName}`;
    }
  }
@computedFrom tells the binding system which expressions to observe. When those expressions change, the binding system will re-evaluate the property (execute the getter). This eliminates the need for dirty checking and can improve performance. The @computedFrom parameters can be simple property names as shown above or more complex expressions like @computedFrom('event.startDate', 'event.endDate').
The debounce binding behavior is another rate-limiting binding behavior that prevents the binding from being updated until a specified interval has passed without any changes. Debounce binding's one of the use can be determined in a common use case is a search input that triggers searching automatically.
animator-velocity() in Aurelia is used to make things further lively and interesting. This is when the element you will be using will be more exciting performing certain animations as you like to. Here in the Aurelia animation solutions, we can use simply the same library. Here it actually uses a very simple interface and has great flexibility in performing or creating animations.
Throttle in Aurelia is used for rate limiting. Binding behavior is basically a process where the binding process continues throughout the whole cycle. The Aurelia ships consist of multiple behaviors which are basically used to enable similar scenarios. In this case, the first binding that happens is the throttle binding process. Here it just limits the continuous two way binding of the view model and on the other hand the one-way binding of the view when it is updated.
By default, the DefaultLinkHandler skips click hijacking in following situations.
 
1. if it's not clicking primary button (left button for right-handed).
2. if any of Alt/Ctrl/Meta/Shift keys is pressed.
3. if the href on <a> element starts with # (link to local hash), or it's a full url like https://... or ftp://....
4. if the <a> has a target attribute and it is not targeting the current window.
  <a href="/some/link" target="_blank">Skip Hijacking</a>
  
  <a href="/some/link">Does Not Skip</a>
  <a href="/some/link" target="_self">Does Not Skip</a>
  <a href="/some/link" target="name-of-current-window">Does Not Skip</a>​
  
5. if the <a> has special attribute download, or router-ignore, or data-router-ignore.
  <a href="/some/link" download>Skip Hijacking</a>
  <a href="/some/link" download="">Skip Hijacking</a>
  <a href="/some/link" router-ignore>Skip Hijacking</a>
  <a href="/some/link" router-ignore="">Skip Hijacking</a>
  <a href="/some/link" data-router-ignore>Skip Hijacking</a>
  <a href="/some/link" data-router-ignore="">Skip Hijacking</a>​
The data-router-ignore is introduced to play nice with another Aurelia feature: automatic data attribute creation.
<a href="/some/link" data-router-ignore.bind="condition || null">Conditional Skip Hijacking</a>
Here Aurelia will dynamically add/remove attribute data-router-ignore when condition changes. Note || null is necessary because Aurelia only removes the data attribute when the bound value becomes null or undefined, it doesn't remove the data attribute when bound value is 0 or "" or even false.
 
In comparison, <a href="/some/link" router-ignore.bind="condition || null">Does not work</a> does NOT add/remove attribute router-ignore. Aurelia only does that for data- or aria- attributes.
You'll learn how to add validation to your applications using a fluent rule API and minimal changes to your templates.
 
To get started you'll need to install aurelia-validation using npm install aurelia-validation or jspm install aurelia-validation. Afterwards, add .plugin(PLATFORM.moduleName('aurelia-validation')) to the configuration in your main.js to ensure the plugin is loaded at application startup.
 
Defining Rules :  Aurelia Validation's standard rule engine uses a fluent syntax to define a set of rules.

There are five parts to the syntax :
 
* Selecting a property using .ensure

*
Associating rules with the property using .required, .matches, etc

* Customizing property rules using .withMessage, .when, etc

* Sequencing rules using .then

*
Applying the ruleset to a class or instance using .on
The validate binding behavior enables quick and easy validation for two-way data-bindings. The behavior registers the binding instance with a controller, enabling the system to validate the binding's associated property when the validate trigger occurs (blur / change). The binding behavior is able to identify the object and property name to validate in all sorts of binding expressions :
 
Automatic Binding Validation : 
  <input type="text" value.bind="firstName & validate">
  
  <input type="text" value.bind="person.firstName & validate">
  
  <input type="text" value.bind="person['firstName'] | upperCase & validate">
  
  <input type="text" value.bind="currentEntity[p] & debounce & validate">​
  
validate accepts a couple of optional arguments enabling you to explicitly specify the rules and controller instance:
 
Explicit Binding Validation : 
  <input type="text" value.bind="firstName & validate:personController">
  
  <input type="text" value.bind="firstName & validate:personRules">
  
  <input type="text" value.bind="firstName & validate:personController:personRules">​
  
The validate binding behavior obeys the associated controller's validateTrigger (blur, focusout, change, changeOrBlur, changeOrFocusout, manual). If you'd like to use a different validateTrigger in a particular binding use one of the following binding behaviors in place of & validate :
 
* & validateOnBlur : the DOM blur event triggers validation.

* & validateOnFocusout : the DOM focusout event triggers validation.

* & validateOnChange : data entry that changes the model triggers validation.

* & validateOnChangeOrBlur : DOM blur or data entry triggers validation.

* & validateOnChangeOrFocusout : DOM focusout or data entry triggers validation.

* & validateManually : the binding is not validated automatically when the associated element is blurred or changed by the user.
The controller exposes properties that are useful for creating error UIs using standard Aurelia templating techniques :
 
results : An array of the current ValidateResult instances. These are the results of validating individual rules.

errors : An array of the current ValidateResult instances whose valid property is false.

validating : a boolean that indicates whether the controller is currently executing validation.

Assuming your view-model had a controller property you could add a simple error summary to your form using a repeat :
  <form>
    <ul if.bind="controller.errors">
      <li repeat.for="error of controller.errors">
        ${error.message}
      </li>
    </ul>
    ...
    ...
  </form>
If you have two forms that need to be independently validated, it is of course recommended you implement them in separate components. However, it is technically possible to do two or more independant validations in the same component by creating multiple validation controllers.
 
For instance : imagine you're building an order form for an Italian restaurant. The customer can order pizza or pasta. If the customer makes a mistake in ordering a pizza, they should be able to order a pasta regardless. In that case your view model would look like this :
 
ViewModel with multiple validation controllers : 
 import {inject, NewInstance} from 'aurelia-framework';
  import {ValidationController, ValidationRules} from 'aurelia-validation';
  
  @inject(NewInstance.of(ValidationController), NewInstance.of(ValidationController))
  export class ItalianRestaurant {
    pizza;
    pasta;
  
    pizzaValidationController;
    pastaValidationController
  
    constructor(pizzaValidationController, pastaValidationController) {
      this.pizzaValidationController = pizzaValidationController;
      this.pastaValidationController = pastaValidationController;
  
      const pizzaRules = ValidationRules
        .ensure((res: ItalianRestaurant) => res.pizza).required()
        .rules;
      this.pizzaValidationController.addObject(this, pizzaRules);
  
      const pastaRules = ValidationRules
        .ensure((res: ItalianRestaurant) => res.pasta).required()
        .rules;
      this.pastaValidationController.addObject(this, pastaRules);
    }
  
    orderPizza() {
      this.pizzaValidationController.validate()
        .then(result => {
          if (result.valid) {
            alert("Ordering this pizza: " + this.pizza);
          }
        });
    }
  
    orderPasta() {
      this.pastaValidationController.validate()
        .then(result => {
          if (result.valid) {
            alert("Ordering this pasta: " + this.pasta);
          }
        });
    }
  }

In your view you need to take care to associate each input with the correct validation controller :

I18N View : 

<template>
    <form validation-errors="errors.bind: pizzaErrors; controller.bind: pizzaValidationController"
          submit.delegate="orderPizza()">
      <label for="pizza">Choose a pizza:</label>
      <input id="pizza" value.bind="pizza & validateManually:pizzaValidationController">
      <span class="help-block" repeat.for="errorInfo of pizzaErrors">
        ${errorInfo.error.message}
      </span>
      <input type="submit" value="Order pizza!">
    </form>

    <form validation-errors="errors.bind: pastaErrors; controller.bind: pastaValidationController"
          submit.delegate="orderPasta()">
      <label for="pasta">Choose a pasta:</label>
      <input id="pasta" value.bind="pasta & validateManually:pastaValidationController">
      <span class="help-block" repeat.for="errorInfo of pastaErrors">
        ${errorInfo.error.message}
      </span>
      <input type="submit" value="Order pasta!">
    </form>
  </template>


In the forms above you can see that each validation-errors attribute and each validateManually binding behavior is bound to the appropriate validation controller.

This library is part of the Aurelia platform and contains a plugin that provides a virtualized repeater and other virtualization services. This plugin enables "virtualization" of list through a new virtual-repeat.for. When used, the list "virtually" as tens or hundreds of thousands of rows, but the DOM only actually has rows for what is visible. It could be only tens of items. This allows rendering of massive lists of data with amazing performance. It works like repeat.for, it just creates a scrolling area and manages the list using UI virtualization techniques.
The UI Virtualization plugin allows you to virtually scroll lists comprised of many items, it also provides an infinite scroll attribute which allows you to fetch more items when the user scrolls the container. The infinite-scroll-next attribute accepts a callback function in your view which receives three arguments when fired.
 
* Argument #1 An integer value that represents the current item that exists at the top of the rendered items in the DOM.

* Argument #2 A boolean value that indicates whether the list has been scrolled to the bottom of the items list.

* Argument #3 A boolean value that indicates whether the list has been scrolled to the top of the items list.
1. <template></template> is not supported as a root element of a virtual repeat template, because virtualization requires item heights to be calculatable. With <template></template>, there is no easy and performant way to acquire this value.

2. Similar to (1), other template controllers cannot be used in conjunction with virtual-repeat, unlike repeat i.e: built-in template controllers: with, if, replaceable cannot be used with virtual-repeat. You can easily work around this constraint by nesting other template controllers inside the repeated element, with <template></template> element.

For example : app.html
  <template>
    <h1>${message}</h1>
    <div virtual-repeat.for="person of persons">
      <template with.bind="person">
        ${Name}
      </template>
    </div>
  </template>
3. Beware of CSS selector : nth-child and similar selectors. Virtualization requires appropriate removing and inserting visible items, based on scroll position. This means DOM elements order will not stay the same, thus creating unexpected :nth-child CSS selector behavior. To work around this, you can use contextual properties $index, $odd, $even etc... to determine an item position, and apply CSS classes/styles against it, like the following example :
  <template>
    <div virtual-repeat.for="person of persons" class="${$odd ? 'odd' : 'even'}-row">
      ${person.name}
    </div>
  </template>​
  
4. Similar to (3), virtualization requires appropriate removing and inserting visible items, corresponding lifecycle of items view will also be triggered while inserting (bind, attached) or removing (unbind, detached)
The ComponentTester exposes a set of properties that can be handy when doing asserts or to stage a component in a specific way. Here's a list of what is available :
 
* element : The HTML element that gets rendered.

*
viewModel : The view-model for the component.

*
configure : The ComponentTester's configure method can be overwritten in order to set it up with custom configuration or get a reference to the container instance.

*
dispose : Cleans up the DOM after a test has run.

*
bind : Manually handles bind.

*
unbind : Manually handles unbind.

*
attached : Manually handles attached.

*
detached : Manually handles detached.

*
waitForElement and waitForElements : Waits until one or several elements are present / absent. See below.
End-To-End (E2E) testing is all about testing your application against specific scenarios. From a requirements-engineering-perspective you'd call those User Stories. Essentially, these stories describe a series of actions a user performs to achieve a certain goal. So by assembling a bunch of these - referred to as a test suite - you are able to verify that your web app acts as expected. The key to success, of course, lies in the amount and quality of tests written.
 
With E2E testing you are not interacting with the app's code per se, but with the app's interface. This is different than unit tests, which take care of isolated parts of the application - called units - by verifying them through the removal or mocking of other parts. It's important to note that one method of testing does not replace the other, so don't take this article as an excuse to skip unit testing.
Server Side Rendering is a concept where the server gets more responsibilities, namely rendering the application on the server and sending the fully rendered page back to the client. By doing this the user will see a rendered page more quickly, before the bundles are loaded and the application has started client-side. Since the page that's returned by the server is fully rendered (the page content is already in the HTML), your site will receive a higher ranking by search engines.
 
Server Side Rendering is only feasible because of something called isomorphism. An isomorphic framework allows you to run one application both on the client and the server. Aurelia is such a framework.
In the aurelia_project directory there is a file called aurelia.json. This file is the centralized settings for all the gulp tasks like build and test. We will show you more details of this file when talking about various customization.
When creating a new project using the Aurelia CLI, you are presented with a wizard to select a bundler, a module loader, CSS preprocessor and more.
 
On top of all choices, you first need to choose a bundler: either Webpack (the default bundler) or CLI's built-in bundler (the alternative bundler).
 
Webpack : 
* Webpack is the default choice for both ESNext and TypeScript applications.
 
* Webpack is a bundler with built-in module loader. If you choose to use Webpack then you don't need a separate module loader. Webpack is powerful and popular, but it could be a daunting task to set up Webpack from scratch. Aurelia CLI generates a battle-tested Webpack configuration file for your app, provides a solid base for further customization if you ever need to.
 
CLI's Built-in Bundler : 
* Aurelia CLI ships with an in-house made bundler providing similar functionality of Webpack but with much simpler configuration. If you have no experience on Webpack, we recommend using the built-in bundler.
 
* The built-in bundler is paired with module loader RequireJS or SystemJS.
 
* RequireJS has been around for a very long time, it's the reference module loader for AMD module format. Comparing to SystemJS, it is considered a bit more mature and stable, but with fewer features.

* SystemJS is a "Dynamic ES module loader", the most versatile module loader in JavaScript world, supporting AMD/CommonJS/UMD or Native ESNext module format. This gives you most freedom at runtime.
There are differences between the Aurelia CLI bundler and the Webpack bundler. When you are migrating an existing application from the integrated bundler to Webpack there are a few things to keep in mind.
 
Webpack requires the use of PLATFORM.moduleName() for any module reference in the code, except for the import statements. PLATFORM can be imported using import {PLATFORM} from 'aurelia-pal';.
 
A few examples :
 
* in main.js or main.ts do aurelia.setRoot(PLATFORM.moduleName('app')).
* for routes do { ...., name: 'users', moduleId: PLATFORM.moduleName('./users'), ... }
* @useView(PLATFORM.moduleName('my-view.html'))
* .resources(PLATFORM.moduleName('resources/index'))
* when Webpack cannot find a module even though it exists, you likely are missing a PLATFORM.moduleName for that module

The Aurelia CLI bundler gets its bundle configuration from the aurelia_project/aurelia.json file. This is different for Webpack, where the bundle configuration is inside webpack.config.js. Webpack projects created by the CLI use Aurelia's Webpack Plugin, which you'll find in webpack.config.js.
 
If you use SASS or LESS, then you are going to have to import the stylesheets differently. When you include stylesheets and use the Aurelia CLI bundler, then your <require> statements will have the .css extension: <require from="styles/my-stylesheet.css"></require>. When you use Webpack you have to change this into the .sass or .less extension: <require from="styles/my-stylesheet.sass"></require>.
There are a few steps involved to update the Aurelia CLI to a newer version. In this chapter, these steps will be explained.
 
Good thing to know is that Aurelia CLI is actually installed twice, once globally and once locally. The globally installed Aurelia CLI (npm install aurelia-cli -g) can be found in your user profile and the local one lives inside the node_modules folder of your project. The global Aurelia CLI is used when you're not inside a project directory, for example when you create a new Aurelia CLI project using au new. Inside a project directory, however, the local version of Aurelia CLI is used. That allows you to use different versions of the Aurelia CLI per project.
 
Since the CLI is installed both globally and locally, you need to update both. First, run npm install aurelia-cli@latest -g to update the CLI globally, and run npm install -D aurelia-cli@latest from the project directory to update the local Aurelia CLI.
 
We're continuously improving the project setup to make development better and easier. This sometimes involves updating Gulp tasks. So when you want to update an existing project, you'll want to update the Gulp tasks as well. The recommended way to do this is to update the CLI globally and create a new project using au new. Then you can copy over the tasks in the aurelia_project/tasks directory to your own project.
 
Always check out the release notes on the Aurelia blog as they may contain additional instructions for updating the CLI.