← Back to index

Preparing for the future of AngularJS

Created: 2015-09-22 21:36  |  Source: https://www.airpair.com/angularjs/posts/preparing-for-the-future-of-angularjs

Preparing for the future of AngularJS

Table of Contents

John-Philip Johansson
John-Philip Johansson
John-Philip is a passionate programmer and focuses on the user experience. Developing solutions is a wonderful thing and he wants to spread that love.


Want help from a top angularjs developer? John-Philip Johansson is available for live angularjs pair programming on AirPair. >> Video chat with John-Philip Johansson

1 Introduction

Angular is a great framework, with a lot of users. It also has a really passionate team behind it, with people like Brad Green, Igor Minar, Miško Hevery, Pete Bacon, and others.

When they unveiled their current plans for Angular 2.0 on ng-europe after a few months of silence, the Internet exploded. Things just looked so different. But there are good reasons to keep a level head. Breaking changes are to be expected in such a major release. It's important and healthy, but it's not always fun having to relearn concepts or rewrite code.

So the question on everybody's mind is: "what's the migration path for 2.0?".

"It's really hard for us to build a bridge to a city that doesn't exist yet." -- Brad Green, Engineering Director, Angular core team

The simple truth is that 2.0 doesn't exist yet. There are ideas, but the Angular team wants to work with us developers to figure out what it should be. We can help by following along on the Github repo, official blog and the Design docs.

... we must find a fine balance between supporting and improving the existing Angular, while building the best Angular yet. ... This is why I need you to step up! Help each other. Help us triage issues and review pull requests. Answer questions on the mailing list, stackoverflow etc. -- Igor Minar, Angular 2.0 core team

Here we'll be taking a look at where Angular comes from, to get an idea of where it might go. The goal is to gather tools that helps us prepare, write cleaner code, and hopefully interact with the Angular team to help them help us.

2 Understanding Angular

Angular 2.0 is still a long way off so no one really knows exactly what it's going to be like. By understanding where Angular comes from and where the Internet is going we can write our code in a way that aligns with those goals.

2.1 Problems Angular has tried to solve

Angular grew from handling HTML forms to build large client side applications. Some of the most basic features are probably the most eye catching ones, like data-binding and the MV* pattern. Those are great, but as we know Angular is much more than that.

2.1.1 Modules

One common problem with today's JavaScript is that while the interpreters have improved to such a level that we can write huge applications, the language itself doesn't support architecting our code in a way to keep things manageable along with the growth.

The most fundamental feature is being able to group and isolate pieces of code. This is why we've seen libraries like RequireJS. As Angular implemented its own $q and jQuery (jqLite) they also created angular#module.

2.1.2 Controllers, providers, and directives

One of the most common use cases in web development is creating custom pieces of elements on a page, like tabs or buttons with spinners in them. Today the web lacks a good way to separate concerns and easily manipulate the DOM. While things are on their way (see section 2.2) we've had the need for some time.

jQuery is great for controlling the DOM in a direct way. We call that an imperative model. To help developers transition to Angular it has supported that way of thinking. But Angular has at the same time tried to give us a more declarative model where we're more concerned with what, rather than how. Data binding is probably the most notable of these features as we can just use our JS data in the HTML, rather than grabbing the element and pushing in the value ourselves.

Every developer has their own preferred way of splitting their code (besides modules), but in an effort to allow larger teams to work together Angular chose to be a bit opinionated. This structure are the controllers, services, filters, directives, etc. that we use today.

2.2 What's happening in the rest of the world

The Angular team does a great job in following the standardization plans while still looking towards the future and giving us tools today. W3C is working on Web Components and WHATWG on the Component model. At the same time Ecma International is working on ECMAScript 6.

Angular 2.0 looks very different from what we're used to. But if we look outside of Angular we start to understand why. Angular wants to add to what browsers can do, not replicate it. So as browsers can do more things, Angular has to do different things and allow the browser to do the things that Angular used to do.

2.2.1 Web Components

The need for creating reusable pieces of code for websites hasn't gone unnoticed. Platform and language makers have their own ways of doing this - on the server. We want to do it in the browser though, and be able to extend existing DOM elements. So far the standards body W3C are dividing it into three pieces:

Shadow DOM gives us the ability to encapsulate our "blocks" (custom elements, directives) in a way that doesn't leak styling or scripts onto other parts. But we'll probably have to wait for browsers to implement this as it's much harder to polyfill.

Custom Elements we pretty much recognize from Angular's directives.

HTML Imports we also recognize from Angular, as directives can pull in HTML files.

Web components also need Template Element. Luckily that's already a W3C recommendation.

As the Angular team describes it:

"By combining these four capabilities web developers can create declarative components (Custom Elements) which are fully encapsulated (Shadow DOM). These components can describe their own views (Template Element) and can be easily packaged for distribution to other developers (HTML Imports)."

It's worth trying these things out with Polymer or X-Tag. They're projects that polyfill Web Components so we can use them as they're planned, today.

2.2.2 ECMAScript 6

ECMAScript is the standard that the browsers implement as JavaScript. We're currently on ECMAScript 5.1. There are many great articles on the features of ES6, including one from AirPair's CEO.

What keeps coming up again and again are classes and modules. Those will most likely influence how we write Angular apps. Arrow functions, default parameters, and rest parameters will also be useful. But most of it is just syntactic sugar and we'll be able to write apps like we're used to, if we want. Erik Arvidsson demonstrated this at ng-europe

2.3 Current plans for Angular 2.0

Angular 2.0. It is essentially a re-imagining of AngularJS for the modern web -- Rob Eisenberg, Angular 2.0 core team

There's no planned release date for Angular 2.0 and there's nothing definite about it yet. Also we'll probably get at least one more 1.x before 2.0. If we keep our code updated with every release then the transition should be a lot smoother. But even so there are several very large changes. Some even say that Angular 2.0 looks like a completely different framework, for good or bad.

At ng-europe the Angular team seemed to be describing a wedding in Game of Thrones as much as describing the new 2.0. They've admitted it was a bit drastic in it's presentation, as the concepts will still be used and it's just the current implementation that is dead. The major changes concern:

  • Controllers;
  • Directive definition object;
  • $scope;
  • Modules;
  • jqLite;

2.3.1 JavaScript

As ES6 is almost here the Angular team is looking ahead. While the Angular 2.0 source will be possible to transpile to ES5, it will be based on ES6 and add a few things on top of it. That's being done under the name AtScript, which Google says is "NOT a new language". They describe AtScript as ES6 + Types + Annotations + Introspections.

2.3.2 Controllers

If we look at a lot of different apps today we would probably see the same thing as the Angular team has seen in the 1600+ projects used internally at Google: controllers aren't really needed. At least not as a standalone entity, but still useful for directives. As 2.0 introduces three different directives our controller code will now live within them.

2.3.3 Directive definition object

We might miss that big ball of fun that is the DDO, but probably we won't. Instead directives will use the declarative support in ES6 and AtScript. As was demonstrated at ng-europe with this sample:

javascript// Angular 2.0 directive example
import {TodoStore} from './store';

@ComponentDirective({
  directives: [TabContainer, TabPane, NgRepeat]
})
class SantaTodoApp {
  constructor(store:TodoStore) {
    this.newTodoTitle = '';
  }
  addTodo: function() { ... }
  removeTodo: function(todo) { ... }
  todosOf: function(filter) { ... }
}
Like learning from posts like this? Subscribe for more!

2.3.4 $scope

Removing the $scope object isn't as bad as it might sound. We will still have a "scope" concept and it will be bound to the directive. Having different kinds of scope, like isolated and non-isolated, can easily lead to issues. So it's best to keep things simple and focus on isolated scopes.

2.3.5 Module

As we've seen, the world around Angular is progressing and 2.0 plans to synced with that. So 2.0 will drop the custom angular#module() and use ES6 modules instead.

2.3.6 jqLite

jQuery has been supported in Angular since day one. That support isn't going away, but Angular will no longer include it's own miniature version (jqLite). It's also in line with how Angular prefers declarative over imperative (as discussed in 2.1.2).

3 Preparing for Angular 2.0

There are many changes happening, both inside and outside of the "Angular world". The best way to be able to transition to Angular 2.0 is to keep our apps updated as new Angular versions are released. Staying on 1.2 or 1.3 until 2.0 is released is probably going to result in a huge undertaking. Still, from what we've covered so far there are a few things we can start doing today that not only helps us prepare for the future but also write better code. But it's important to remember that 2.0 is not done and can change in any way at any time.

3.1 Start writing in ES6

Currently the Angular 2.0 team intends to allow apps to be written in ES5, ES6, AtScript, CoffeeScript, TypeScript, etc. But as the web is moving towards ES6, so should we. The most notable usage will be in using ES6 modules to help in transitioning away from angular#module(). And it's worth looking into classes as alternatives to our functions.

There are many tools that helps us code in ES6 today but since the Angular team uses Google's Traceur then that's a good starting point. It also has a fairly impressive feature list.

First let's look at how transpiled ES6 looks like when using Traceur. Given this simple piece of ES6:

javascript// ES6
class Greeter {
  sayHi(name = 'Anonymous') {
    console.log(`Hi ${name}!`);
  }
}

var greeter = new Greeter();
greeter.sayHi();
Like learning from posts like this? Subscribe for more!

We get this output in ES5:

javascript// ES5
"use strict";
var Greeter = function Greeter() {};
($traceurRuntime.createClass)(Greeter, {sayHi: function() {
    var name = arguments[0] !== (void 0) ? arguments[0] : 'Anonymous';
    console.log(("Hi " + name + "!"));
  }}, {});

var greeter = new Greeter();
greeter.sayHi();
return {};
Like learning from posts like this? Subscribe for more!

It looks a bit scary but it's important to remember that we won't be touching the output. If we look a bit closer at the output we see a variable we haven't seen before: $traceurRuntime. That means that we need to include traceur-runtime.js in our app. Some features, like modules, can be used and transpiled without needing the runtime.

Google has a getting started guide and an compiling offline guide that covers the basics. There are plugins for Grunt, Gulp, and Broccli that help setting up a nice workflow. To just play around with Traceur we can use Google's REPL page or jsBin (just change "JavaScript" to "Traceur").

TodoMVC is a nice website that compares there implementation of a simple Todo app in various frameworks. There is of course an Angular version, but more interesting are probably the Angular + Require and Angular + TypeScript implementations.

3.2 Remove dependencies on $scope

There's a lot to be understood about scopes and not knowing them often leads to unexpected behaviour (like this or this). Suffice to say, the prototypical inheritance and binding on primitive types are just two of the reasons that $scope is problematic and we'd be better of without it.

From Angular 1.1 we've been able to attach our view properties on the controller instead of the $scope object. Given that $scope is being removed in 2.0 it's a great incentive to start doing this now. This means attaching our functions and values to this instead of $scope. This is called controller as.

javascript// Instead of doing this:
app.controller('TodoCtrl', function ($scope) {
  $scope.input = 'ex. buy milk';
});

// Do this:
app.controller('TodoCtrl', function () {
  this.input = 'ex. buy milk';
});
Like learning from posts like this? Subscribe for more!
markup<!-- Then instead of this: -->
<div ng-controller="TodoCtrl">
  <input type="text" ng-model="input" />
</div>

<!-- Do this: -->
<div ng-controller="TodoCtrl as todo">
  <input type="text" ng-model="todo.input" />
</div>
Like learning from posts like this? Subscribe for more!

[Try a demo]

The documentation for 1.3 give some compelling reasons for controller as:

  • Using controller as makes it obvious which controller you are accessing in the template when multiple controllers apply to an element.
  • If you are writing your controllers as classes you have easier access to the properties and methods, which will appear on the scope, from inside the controller code.
  • Since there is always a . in the bindings, you don't have to worry about prototypal inheritance masking primitives.

If we need to use $evalAsync, etc, we will still need to use the $scope object. For $watch there is usually a different way.

3.3 Match controllers with directives

In Angular 1.3 it's no longer supported to add Controllers to the global scope. But we should take a step further and stop writing controllers as completely separate entities. Todd Motto has an interesting article on rethinking AngularJS controllers. By moving the logic from our controllers to services we can create thinner controllers that just handles interaction with the DOM. That makes the element the controller is attached to a prime candidate to be turned into a directive. Now we can package the two together, as others have suggested. This turns into a nice pattern that will smooth things out when controllers are no longer available in 2.0.

As the scope concept takes shape in 2.0 we should rely more on isolated scope as that also leads to cleaner code. bindToController was introduced in 1.3 to help us use isolated scope on the controller with a directive:

javascriptapp.directive('todo', function () {
  return {
    scope: {},
    controllerAs: 'TodoCtrl',
    controller: 'TodoCtrl',
    bindToController: true,
    template: ...
  };
});
Like learning from posts like this? Subscribe for more!

[Try a demo]

3.4 Transition to ES6 modules

As ES6 will have native support for modules we'll no longer need Angular's version. It can be a good practice to start transitioning away from it today.

Now that the syntax has been finalized we can start using it, and it looks like this:

javascript// lib.js
export function square(x) {
    return x * x;
}

// main.js
import { square } from 'lib';
Like learning from posts like this? Subscribe for more!

As we saw in section 3.1 we can use this but would then be dependent on the Traceur runtime. Luckily Traceur can compile modules to output RequireJS/CommonJS syntax with this simple command:

bash$ traceur --dir ./src ./dist --modules commonjs
Like learning from posts like this? Subscribe for more!

Since RequireJS is currently more common it might be interesting to see how to use it with Angular. If nothing else, we can start writing it in ES5 directly.

javascript// Declaring a service.
define(['app'], function (app) {
  app.factory('todoStorage', function () {
    ...
  });
});

// Using the service.
define(['app', 'services/todoStorage'], function (app) {
  return app.controller('TodoController', ['todoStorage', function(todoStorage) {
    ...
  }]);
});
Like learning from posts like this? Subscribe for more!

Full example from TodoMVC.

4 Back to the future

2015 is going to be a really exciting year. ES6 will be finalized and browsers start implementing it. Web Components will have come much further. And if we don't get Angular 2.0, we certainly will get more info on it.

What is most important to remember is that we're all trying to create a better web. The Angular team doesn't get specs on stone tablets from above. They interact with the community, examine thousands of projects, and think really hard.

The best thing we can do for 2.0 is to experiment with how we want it to be. This article just describes some tools to do it with, so it's now up to us to do it and share our findings with the Angular team.

Further reading

Videos

Podcasts

Need 1 on 1 expert help?
PAIR UP with

experts like

John-Philip Johansson
Login

Like this post? Get angularjs content like this by email