AngularJS has been a huge success. More than 1.1 million developers have embraced this platform and created thousands of applications using it. Writing complex applications in JavaScript can be challenging, and AngularJS made it approachable. In a language devoid of good design patterns and strict rules, AngularJS brought sanity and consistency. But let's be honest, although AngularJS was a huge improvement over writing JavaScript by hand, it did have some issues. Learning AngularJS was a steep curve. Buying into it was embracing the whole platform. And most of all, there were so many ways to do it incorrectly, and so many ways to do it better than the last developer.

Over time, as browsers improved and Web technologies were applied to more than just browsers, AngularJS 1 didn't take full advantage of those scenarios. Plus, TypeScript, which, in my mind is the single most important innovation in JavaScript since fast JavaScript engines, always felt like an afterthought in AngularJS 1. Yes, although you could use TypeScript, it was hard to take full advantage of it unless you consciously attempted to do so. As a result, in an AngularJS 1 world, you are more likely to see lots of JavaScript or incomplete usage of TypeScript.

This is not unexpected: Times change and technologies evolve. AngularJS 2 is a natural evolution of AngularJS 1. Angular JS 2 brings it up to date with modern Web standards, better design patterns, and takes advantage of what's new and awesome today.

Why Bother with AngularJS 2

There are four main reasons you should seriously consider AngularJS 2:

  • It is fast. Very fast. It takes full advantage of modern Web browsers and defaults to using the capabilities they offer to give you the best performance. If you wrote the same functionality in AngularJS 2 as you wrote for AngularJS 1, AngularJS 2 will most likely far outstrip the performance of AngularJS 1.
  • It is portable. Although it relies on the newest standards, it uses polyfills to support almost every browser you care about. Even IE9 is supported.
  • It allows for a more logical code structure than its predecessor. AngularJS 1 had the bad habit of polluting your HTML, not giving you more control on CSS, and forcing you to think in MVC. AngularJS 2 allows you to do MVC, or Flux, or any other design pattern you wish. It also allows you to logically design and arrange your application in components rather than controllers. And finally, it tends to pollute your HTML less, and only in ways that semantically enhance HTML. You don't need ng-href or ng-src, but you can still have your own tags, like <customer/>, etc.
  • And the best part about AngularJS 2 is that it's easier than AngularJS 1. I'll be honest, it took a lot of time to truly master AngularJS 1. And there were so many ways to mess it up. Parent scopes can be so complicated. As my applications got bigger, my head exploded. Developers smarter than me crafted amazingly intricate card houses that collapsed easily. I felt like an idiot. And this was after a few years of AngularJS 1. AngularJS 2, on the other hand, felt a lot more logical, and it was easier to understand and learn. I find myself more productive in AngularJS 2, and I have the confidence that I'm writing more reliable and easier-to-maintain code. Much more so than AngularJS 1.

The obvious elephant in the room of course is that AngularJS 2, at the time of writing this article, is still in beta. Still, I like AngularJS 2 so much that even in beta, I have no reservations in recommending this platform for new development over AngularJS 1, especially if your release date is in the second half of 2016.

Thinking in AngularJS 2

AngularJS 2 requires you to think differently. There are some key differences compared to AngularJS 1, features you need to learn and decisions you need to make. The good news is that even though there are differences between AngularJS 1 and AngularJS 2, many concepts port over. As an AngularJS 1 developer, you'll clearly see the improvements where you see the differences. As a new-to-AngularJS 2 developer, you'll find the new syntax and features easier to learn.

With that, let me go through the various differences, features, and key decisions.

Language Choices

JavaScript is evolving. It needs to, because the original language simply isn't going to scale to the level of the complex applications that you need to build. When writing for AngularJS 2, you have various choices:

  • ES5: The obvious advantage of using ES5 is that it's only JavaScript and it needs no compilation. But it's not strongly typed, and it doesn't offer the code structure advantages of other alternatives.
  • ES6: ES6 is a superset of ES5. Although it does give you some better code structure building blocks, it isn't strongly typed, and it needs a compilation step. At the end of the day, it's JavaScript, and with time, browsers will support ES6 natively. It's sure taking a very long time for them to do so.
  • TypeScript: TypeScript is a superset of ES6. It's strongly typed. It gives you much better code structure building blocks, but it requires a compilation step. At the end of the day TypeScript is JavaScript - okay, it's a superset of JavaScript, but you can rename your .js to .ts and pretend it's JavaScript.
  • Dart: Dart seems to offer the worst of all worlds. It isn't JavaScript and it requires compilation, but it gives you better code structure alternatives. Because it's not a super set of ES5, ES6, or TypeScript, using Dart feels like using an entirely different language that doesn't mentally translate into JavaScript. At least, not easily.

Given the above choices, I feel that we have a clear winner, and that's TypeScript. I'm going to write my AngularJS 2 code in Typescript, and apparently the AngularJS 2 team is doing so too. You are, however, free to use ES5, ES6, or Dart. But I don't see why you wouldn't prefer to use Typescript.

Components versus Controllers

AngularJS 1 required you to create a controller. A controller was the fundamental “brain” of your application. It was way too easy to abuse the pivotal role of a controller in AngularJS 1, which is why the best practice was to separate most of the logic into services that the controller could use. A typical AngularJS 1 controller looks like the one shown in Listing 1.

Listing 1: AngularJS 1 Controller

(function () {
    angular
        .module('app', [])
        .controller('appController', appController)

    function appController() {
        var vm = this;
        vm.name = "Sahil";
    }
})();

You could use this controller as shown in Listing 2.

Listing 2: Using an AngularJS 1 controller

<body ng-app="app" ng-controller="appController as vm">
    Name: <span ng-bind="vm.name"></span>
</body>

Controllers, over time, became very complex. They had to deal with parent and child scopes. There was no one-size-fits-all approach that you could use, making understanding and debugging the application for the next developer a lot harder. And it forced you to do MVC, whether or not it was the right choice for your application.

AngularJS 2 replaces “thinking in controllers” with “thinking in components.” Components are the central artifact in AngularJS 2.

<my-app>Loading...</my-app>

Using the component shown in Listing 3 is a matter of referencing the selector. The component can nest other components, and it can even give your “tag” its own CSS area, so your CSS doesn't interfere with the page's CSS and vice versa.

Listing 3: An AngularJS 2 component

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<h1>Hello {{name}}<h1>'
})

export class AppComponent {
    name = "Sahil";
}

Bootstrapping

Bootstrapping your app requires explicit action from you. AngularJS 1 allowed you to bootstrap your app by placing certain attributes in your HTML, as shown in Figure 1. Or alternatively, you could bootstrap your app in AngularJS 1 using code also.

Figure 1: Bootstrapping an AngularJS 1 app
Figure 1: Bootstrapping an AngularJS 1 app

AngularJS 2 takes a different approach. AngularJS 2 likes to split your application into components. And it allows you to bootstrap the starter component by importing it as a module first. This can be seen in Listing 4. This gives us a lot of control in modularizing the application. Because the module is a class that you export, you have very clear control of which portions of the module are visible and which are not. You can also bootstrap conditionally; what's perhaps most interesting is the first line in Listing 4. AngularJS 2 imports bootstrap from angular2/platform/browser. This means that the browser is separate from the core AngularJS 2. You could theoretically have different bootstrapping functionality for Cordova/Electron etc.

Listing 4: Bootstrapping an AngularJS 2 app

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'
bootstrap(AppComponent);

Structural Directives

There are three kinds of AngularJS directives: there are components; there's a directive with a template in AngularJS 2; and there's the attribute directive, which can change the behavior or appearance of an element (for example, NgStyle); and structural directives.

Structural directives can alter the structure of the DOM. For instance, ngIf, ngSwitch, ngFor are structural directives.

You've seen structural directives in AngularJS 1. An example can be seen in Listing 5. AngularJS 2 also has support for structural directives. The same example written in AngularJS 2 can be seen in Listing 6.

Listing 5: Structural directives in AngularJS 1

<ul>
    <li ng-repeat="hobby in vm.hobbies">
        <span ng-if="!hobby.hide">
            {{hobby}}
        </span>
    </li>
</ul>

Listing 6: Structural Directives in AngularJS 2

<ul>
    <li *ngFor="#hobby of hobbies">
        <span *ngIf="!hobby.hide">{{hobby | json}}</span>
    </li>
</ul>

As you can see, the syntax is slightly different, but it still works.

Now here is the really interesting part. You can write your own structural directives in AngularJS 2 using the @Directive decorator. This gives you very fine control on exactly how you want the DOM to be modified. Modifying the DOM is one of the most expensive things your application does, so this level of control is definitely very welcome. Sure, you could do this in AngularJS 1, but there, everything was a directive, and writing directives could get complex. AngularJS 2, with its @Directive decorator, puts writing complex directives within the reach of mere mortals.

DataBinding

Databinding is what truly set Angular apart. There are three kinds of databinding that AngularJS supports: Interpolation, one-way databinding, and two-way databinding. Let's look at them:

  • Interpolation, the {{expression}} double-moustache syntax. Both AngularJS 1 and AngularJS 2 support interpolation in exactly the same manner. The key difference is that AngularJS 1 databound to properties on the view model or $scope of the controller. AngularJS 2 databinds to exported properties of the underlying class that the component is implemented as.
  • One way databinding, using ng-bind. This is where AngularJS 2 shows its superiority over AngularJS 1. AngularJS 1 required you to do one way databinding using the syntax shown below:
Name: <span ng-bind="vm.name"></span>

This syntax was functional, but it required you to intersperse attributes that sometimes were not very intuitive. Why am I using ng-bind to change the value of innerText? And what if I wanted to bind to an alternate property such as CSS or width or href? This is where AngularJS 2 uses a much better syntax, as shown here:

<span [innerText]="name"></span>

AngularJS 2 binds to any property of the surrounding element. This is more intuitive to learn and program because there's no hidden meaning of what an ng-bind may do. You know that you're modifying the innerText property, no surprises there. And if you wanted to bind to an event, you'd use a slightly different syntax, like that as shown here:

<button (click)="clickHandler()">Click me</button>

Here, you're binding to the click event of the button. Can you guess how you would bind to the “mouse-up” event? You can think of event binding as the reverse of data binding. Both are one-way bindings.

  • And sometimes, you need two-way databinding. Two-way databinding in AngularJS 1 was implemented as shown here:
<input ng-model="vm.name"></input>

The same affect can be achieved in AngularJS 2 using the “banana in a box syntax” or the [()] expression as shown below:

<input [(ngModel)]="name">

This cleaner syntax of databinding that AngularJS 2 uses has another side benefit: You have fewer directives to learn.

Fewer Directives to Learn

Here's an AngularJS 1 quiz. What did ng-href do? If you remember, you couldn't databind directly to the href property of an anchor tag in AngularJS 1. This is because the browser understood the expression before the result of the expression, thereby breaking your href location. Not good! So you had to create directives like ng-href, ng-src, etc.

Similarly, you had numerous other directives, such as ng-style to modify the style of an element. Or ng-click, ng-blur, etc. to handle events! Because AngularJS 2 allows you to databind with a much more intuitive syntax using the property name instead, all those directives are no longer required.

For example, consider the following AngularJS 1 code:

<img ng-src="vm.link"/>

This can be simplified in AngularJS 2 as follows:

<img [src]="link"/>

And you can guess that you don't need ng-click either, because you can databind directly to the click property. In fact, AngularJS 2 has removed the need for 40+ directives because of this superior syntax.

Services versus Class

It was very easy to abuse controllers in AngularJS 1. As a best practice, we were advised to abstract the heavy lifting to services. But services weren't just services. There were Services, Providers, and Factories ? three ways to create Services (and not very intuitively named, either). And then there were constants, values, and the config method etc. on your module. You had to know exactly which one did what, and which got called before the other. This innate knowledge of the nature of provider versus service versus factory and config versus run, or constant versus value left many of us confused. It made the learning curve unnecessarily steep.

But why did AngularJS 1 have to do all that? It was making up for the shortcomings of JavaScript. AngularJS 2 on the other hand has a class. A class can have a constructor, exported properties, getters and setters, etc. And with TypeScript, the way you write these classes is also very second-nature to those coming from other languages such as C# or Java.

In that sense, AngularJS 2 is much simpler to write and maintain because all those concepts are subsumed by the concept of a class - something you already know.

Dependency Injection

Dependency injection is a software design pattern that implements inversion of control for resolving dependencies. A dependency is an object that can be used (such as a service). An injection is the passing of a dependency to a dependent object (a client) that will use it.

Dependency injection is a strength of AngularJS. It allowed us to change the behavior of code at runtime by passing in the appropriate dependencies. This was achieved in AngularJS 1 using the code shown in Listing 7.

Listing 7: Dependency injection in AngularJS 1

(function () {
    angular
        .module('app', [])
        .controller('appController', appController)

    appController.$inject = ['MyService'];
    function appController(MyService) {
        var vm = this;
        // other details..
    }
})();

It worked, but it had a huge downside: The magic string problem. The MyService is a string in Listing 7, and if you introduced a typo, it broke your code. What was worse, AngularJS 1 allowed you to write variable names such as $scope and $http, and AngularJS 1 attempted to resolve those for you. Because a lot of code online showed such patterns, the typical Google-driven development workflow meant that a lot of developers copy-and-pasted that code and painstakingly made it work. As soon as the code was minified, all the variable names changed and nothing worked anymore.

AngularJS 2 supports dependency injection too, but a better and improved version of it. As can be seen from Listing 8, there is no longer the magic string issue going on. You type the name of the class as it appears, and you can choose to alias it using standard ES6 and TypeScript constructs. You can then set a class variable in the constructor that can hold an instance of the provided service and use it appropriately. This means that your code works the same in both minified and un-minified scenarios. Your dev environment code doesn't break mysteriously when it's thrown into production.

Listing 8: Dependency injection in AngularJS 2

import {Component} from 'angular2/core';
import {MyService} from '/myservice';

@Component({
    selector: 'my-app',
    providers: [MyService],
    ...

Similarities and Other Improvements

As you can see, there are a number of differences between AngularJS 1 and AngularJS 2. But fear not - there are a lot of concepts that port over from AngularJS 1 also. For instance:

  • Modules: AngularJS 1 and AngularJS 2 both have modules. But AngularJS 1 couldn't make use of ES6 modules because ES6 wasn't around when AngularJS 1 was born. AngularJS 2 uses proper ES6 modules, but yes, the concept of modules is still around.
  • Filters: Remember in AngularJS 1 there was a filter called “filter”? Confusing? They've changed the name of Filters to Pipes! It's much more logical, especially given the syntax. But the concept is still around.
  • Routing: Routing in AngularJS 1 has undergone evolution and improvements. The routing in Angular 1.5x is quite similar to routing in AngularJS 2.
  • HTTP: Because you need to interact with the server too. The same concepts apply in Angular1 and Angular2.
  • Events: These are still around, but you have a much better and logical syntax using event emitters. There will be more on that in future articles.
  • Promises: are still in there. AngularJS 2 has chosen to give us another option, built on RxJS, called Observables. Observables can be thought of as a datasource of events that you can filter on. It's a much better architecture and it's come out of reactive extensions for C#. If you've used reactive extensions in either JavaScript or C#, you probably already know that once you go RxJs, you don't go back!

Perhaps the improvement I like the most in AngularJS 2 is much better error messages. As a developer, I've wasted way too much time over poorly worded generic error messages. AngularJS 1 tried, it tried hard to give me a decent error message about a typo. But frequently an ng-click mistyped as ng-clik yielded no error message. Stuff just didn't work! Even when I did get an error message, it looked like a cryptographic version of a SharePoint site collection GUID salted in Russian. I am happy to say that AngularJS 2 error messages are usually a lot cleaner and more intuitive than their AngularJS 1 counterparts.

Summary

This article isn't intended to be an AngularJS 2 tutorial. It's intended to illustrate the key improvements and changes and the reasons behind them. It's intended to illustrate why I'm excited about AngularJS 2 and why any developer should be excited as well. I'm certain that AngularJS 2 will be quite successful. I'm also certain that it will be used in platforms other than just the browser. It will help us build bigger and better applications, applications that will scale better and perform better. I'm truly excited about AngularJS 2, and I hope to talk a lot more about it in future articles.

In the meanwhile, happy coding!