Angular 2.0 And Aurelia An Updated Comparison

Day 2: Angular 2.0 & Aurelia – An updated comparison

The new direction Angular 2.0 is taking created a lot of discussion in the community. Some people love it, some people hate it. Looking at Angular 1.x, most people agree there is room for simplification, performance enhancements and native support of new language features. Not everyone likes the way Angular 2.0 is picking these up though. There is an alternative direction: Aurelia. In this follow-up blog post, I'll make an updated comparison between the two directions. The big question remains: should you keep all your eggs in the Angular basket?

This is second post of our blogger month at Xebia. Every day one of the Xebian post a new blog. You can follow the full series at http://blog.xebia.in/pages/blogger-month-2015/.

A quick recap

This blog post is a follow-up on my earlier conference talk "Angular 2.0 vs Aurelia" at JSChannel 2015 in Bangalore, India. I received some feedback on this video, which I like to take into account in this new blog.

You can see the original video here:

The TL;DW of this video: Angular 2.0 is not always intuitive and requires you to type more code. Aurelia is mostly intuitive but has a small community right now.

Advantages of Angular 2.0 and Aurelia

These are the features that both frameworks present on their respective websites:

Angular 2.0

  • Mobile first – Mobile specific routing
  • Future ready – Written in TypeScript
  • Flexible development – You choose the language
  • Speed and performance – Faster change detection
  • Simple and expressive
  • Comprehensive routing
  • Animations
  • Hierarchical dependency injection
  • Support for Web Components
  • i18n & ARIA

Aurelia

  • Forward thinking – Written in ES2016
  • Modern architecture – Small, focused modules
  • Two-way databinding – Through Object.observe()
  • MV* with conventions – Convention over configuration
  • Broad language support
  • Testable

Putting it in perspective

The above bullets are how the creators present their framework. Some bullet points for one framework apply just as much to the other framework. For example Aurelia supports Web Components and Angular 2.0 brings improvements in testability.

Some other points are a matter of opinion. For example, is Angular 2.0 really more "Simple and Expressive" than Aurelia? Both frameworks are under development. So for a final opinion on that, let's wait for the first stable versions to be released.

Replacing ng-model?

One point of feedback that I received is that the comparison is not entirely fair, because the code examples follow a different approach. In this post, I'd like to make a more fair comparison.

What I did in this conference talk is share my experiences of starting to use both frameworks. If you follow the documentation of both projects, you are guided in a certain direction. The first experience is in line with where the documentation leads you. After further research, it turns out that other directions are also possible.

Let's make a fair side-by-side comparison…

Using ng-model in Angular 2.0

If you dive a little deeper into the Angular 2.0 documentation, it turns out that there is still an ng-model in Angular 2.0. I did mention this in my video. Unfortunately I had no time left to show the results of using ng-model.

Let's translate the code example from the video to use ng-model.

On my first try, I expect the code to be something like this:

<h1></h1>

<ul>
  <li *ng-for="#item of items #index = index">

    <a (click)="remove(index)">X</a>
  </li>
</ul>

<form (submit)="add(newitem);newitem=''">
  <input [(ng-model)]="newitem">
  <input type="submit" value="Add ">
</form>
import {Component, View,
        NgFor, NgModel} from 'angular2/angular2';

@Component({
  selector: 'component-1'
})
@View({
  templateUrl: './components/home/home.html?v=<%= VERSION %>',
  directives: [NgFor, NgModel]
})
export class Home {
  message:string;
  items:string[];

  constructor() {
    this.message = "Hello from Angular 2.0";
    this.items = ['one', 'two', 'three'];
  }
  add(value:string) {
    this.items.push(value);
  }
  remove(idx:number) {
    this.items.splice(idx, 1);
  }
}

However, there are a few problems in this code. If I write this code in the same codebase that I used for my JSChannel talk, there is no way to import NgModel. Instead, that particular version of Angular 2.0 wants us to import formDirectives. If I update that code base to the latest version of angular-seed (at the time of writing this) – then the problem is the other way around: NgModel is accepted but formDirectives is not. However, if I make my own code base based on the latest Angular 2.0 code, then both formDirectives and NgModel are accepted. But then I run into different errors. Either I am doing something wrong or the API is still under construction.

Second, with the initial rendering of the page, the Add button shows "Add undefined" instead of "Add ". If you push this button for the first time, an empty line is added to the items array and the button still says "Add undefined". If you push the button for the second time, the text "undefined" is added to the items array and the button text changes to "Add ". Pushing the button for a third time will again add an empty string. This is easily fixed by explicitly declaring newitems as a member variable of the underlying class.

Third, although the submit triggers the add() method, the code to make newitem empty never gets executed. I tried fixing this by moving this code into the add() method itself. As with the first issue: different versions of Angular 2.0 give varying results.

Here is the code that I expect to work once Angular 2.0 stabilizes:

<h1></h1>

<ul>
  <li *ng-for="#item of items #index = index">

    <a (click)="remove(index)">X</a>
  </li>
</ul>

<form (submit)="add()">
  <input [(ng-model)]="newitem">
  <input type="submit" value="Add ">
</form>
import {Component, View,
        NgFor, formDirectives} from 'angular2/angular2';

@Component({
  selector: 'component-1'
})
@View({
  templateUrl: './components/home/home.html?v=<%= VERSION %>',
  directives: [NgFor, formDirectives]
})
export class Home {
  message:string;
  items:string[];
  newitem:string;

  constructor() {
    this.message = 'Hello from Angular 2.0';
    this.items = ['one', 'two', 'three'];
    this.newitem = '';
  }
  add() {
    this.items.push(this.newitem);
    this.newitem = '';
  }
  remove(idx:number) {
    this.items.splice(idx, 1);
  }
}

The current Angular 2.0 documentation still says that you should use formDirectives instead of NgModel. Given the behavior that I saw in recent updates, I expect them to become interchangeable.

Translating ng-model to Aurelia's value.bind

Aurelia's equivalent of ng-model is value.bind. This works pretty much the same as ng-model in Angular 1.x. Aurelia provides reasonable defaults for one-way and two-way binding. If you want more control, you can replace value.bind with value.one-way or value.two-way. Below is the same code that I presented on JSChannel.

<template>
  <section>
    <h2>${message}</h2>

    <ul>
      <li repeat.for="item of items">
        ${item}
        <a click.delegate="$parent.remove($index)">X</a>
      </li>
    </ul>

    <form submit.trigger="add(newitem);newitem=''">
      <input value.bind="newitem">
      <input type="submit" value="Add ${newitem}">
    </form>
  </section>
</template>
export class Welcome {
  message = 'Hello from Aurelia';
  items = ['one', 'two', 'three'];
  add(value) {
    this.items.push(value);
  }
  remove(idx) {
    this.items.splice(idx, 1);
  }
}

Reference to input element in Angular 2.0

The way I wrote the code in the video, instead of using ng-model, the code used a reference to the input element. If you are aware of the meaning of #newitem, it actually makes sense that you have to add .value after newitem because it is the HTML input element you are refering to.

This is the code written in the video:

import {Component, View, NgFor} from 'angular2/angular2';

@Component({
  selector: 'component-1'
})
@View({
  templateUrl: './components/home/home.html?v=<%= VERSION %>',
  directives: [NgFor]
})
export class Home {
  message:string;
  items:string[];

  constructor() {
    this.message = "Hello from Angular 2.0";
    this.items = ['one', 'two', 'three'];
  }
  add(value:string) {
    this.items.push(value);
  }
  remove(idx:number) {
    this.items.splice(idx, 1);
  }
}
<h1></h1>

<ul>
  <li *ng-for="#item of items #index = index">

    <a (click)="remove(index)">X</a>
  </li>
</ul>

<form (submit)="add(newitem.value);newitem.value=''">
  <input #newitem (keyup)>
  <input type="submit" value="Add ">
</form>

Reference to input element in Aurelia

Later on, I found out that you can create a similar construction in Aurelia. The naming in Aurelia is a bit more intuitive though.

See the result:

<template>
  <section>
    <h2>${message}</h2>

    <ul>
      <li repeat.for="item of items">
        ${item}
        <a click.delegate="$parent.remove($index)">X</a>
      </li>
    </ul>

    <form submit.trigger="add(newitem.value);newitem.value=''">
      <input ref="newitem">
      <input type="submit" value="Add ${newitem.value}">
    </form>
  </section>
</template>

There are no changes required in the JavaScript, so I'll omit repeating that. Also, please note that the <input ref="newitem"> does not require any event listener declaration, like Angular 2.0 requires you to add something like (keyup).

Evaluation

Even after making the comparison more fair, I still keep running into unexpected issues in Angular 2.0 right now. Perhaps that is related to the current state of Angular 2.0. On the other hand, rewriting part of the Aurelia code is again pretty easy and straightforward.

As for the size of the community, Rob Eisenberg send me an e-mail stressing the amount of community work that is happening around Aurelia. Some of the commenters on my video have said that commit counts aren't always the best indicator of community involvement.

Others have stressed the fact that there is no need to migrate from Angular 1.x to Angular 2.0. If you are okay with the state of Angular 1.x, you can continue to use it for a long time.

As for TypeScript, it is a matter of preference. It cannot be denied that TypeScript has traction in the market. It is even possible that some of TypeScript's features get accepted for standardization in future versions of ECMAScript. Let's see how the TC39 decision making process goes.

Conclusion

To answer the question from the introduction text: should you put all your eggs in the Angular basket? In its current state, Aurelia seems more mature than Angular 2.0. From that perspective, I definitely recommend considering Aurelia as an alternative. But let's not write off Angular 2.0 too soon. It has a big community and a lot of traction in the market so I expect Angular 2.0 to grow past its current shortcomings.

Leave a Reply

Your email address will not be published. Required fields are marked *