Angular 2.0 is lot like Angular1 but still different in its own terms and you’ll see why as we go along. Purpose of this article is to migrate one of the simplest Angular1 examples to Angular2 and understand benefits as well as pain-points. For the record, Angular2 aimed to build web applications in three different languages or flavours i.e. JavaScript (ES5/ES6), Typescript(ES6+), and Dart. If you interested in other two then the 5-minute-session will give you a head-start to understand how it could be done. However, I’m going to use Typescript over JavaScript here because in my opinion it feels more natural. This article is for the ones who worked with Angular1 before.
Angular1
Let’s take a simple example (HTML and JS) from my free e-book on Angular1 Directives that explores how data binding works in Angular1. Let us quickly take a look at our good old Angular1 HTML template and then we’ll move to new shiny Angular2 version of it. But for now, notice we’ve used ngBind directive over double-curly notation for data-binding, obviously to avoid FOUC as we all know. Also checkout ngApp directive which was a recommended way to bootstrap an application automatically in Angular1 without using angular.bootstrap
method.
<br>
<html ng-app="App"><br>
<head><br>
<title>HTML/DOM Template in AngularJS</title><br>
<script type="text/javascript" src="../bower_components/angular/angular.js"></script><br>
<script type="text/javascript" src="../js/ch01/angular-template.js"></script><br>
</head><br>
<body><br>
<span>Hello, <span ng-bind="name"></span></span><br>
</body><br>
</html><br>
Here is the JavaScript code for the above example which simply binds a value of name
property on the $rootScope
.
<br>
var App = angular.module('App', []);<br>
App.run(function($rootScope) {<br>
$rootScope.name = 'AngularJS';<br>
});<br>
Now that we’ve our demo up and running, its time to migrate it to Angular2.
Angular2
Let us first update the JS code and walk-through the changes. Give it a very long, hard stare to get familiar with the following snippet, I’ll wait.
<br>
import { NgModule, Component } from '@angular/core';<br>
import { BrowserModule } from '@angular/platform-browser';<br>
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';</p>
<p>@Component({<br>
selector: 'ng-app',<br>
template: '<span>Hello, <span [textContent]="name"></span></span>'<br>
})<br>
class MyAppComponent {<br>
name: string = 'Angular2';<br>
}</p>
<p>@NgModule({<br>
declarations: [MyAppComponent],<br>
imports: [BrowserModule],<br>
bootstrap: [MyAppComponent]<br>
})<br>
export default class MyAppModule {}</p>
<p>platformBrowserDynamic().bootstrapModule(MyAppModule);<br>
Your first reaction would be, “Alright, that looks familiar..!”. Well it is except few things, let us go over one by one. But before that we must know that Angular2 moved from a concept of directives to components to leverage web-components specs so that developers can use Polymer components with Angular2 templates. Basic idea is to break down monolithic application into small pieces i.e. components and plug them together at the end under main component like we have here. Each component should have one or more Classes or Functions to store data (name
in this case) and necessary methods (not defined in the example above). Please note we no longer use $scope
in Angular2 as this is somewhat like CtrlAs syntax from Angular1. When Angular2 instantiates MyApp
class, all properties or methods defined will be accessible via keyword this
.
Update: As per RC5 release, angular2 introduced a concept of NgModule metadata which plays an important role in the compilation process, especially offline compilation. Because of NgModule, Angular2 will able to lazy load components on demand by resolving component dependencies efficiently. So every component should expose a NgModule for other components to import and reuse. Ideally, NgModule should be extracted into it’s own file importing various components, services, pipes, etc. but for the sake of readability, we’ll have it in the same file along with the component.
export statement
Angular2 has adopted modularity at its core unlike Angular1 wherein you could only define modules without any built-in support for lazy loading. Using ES6 export module syntax, you can export functions, objects, or primitives that other classes can use in Angular2. Having one export class per module recommended though. We’ve defined a property, name
with a type string
which is optional in TypeScript.
Import Statement
With the same export class
syntax, Angular2 has organized its code base so that developers can import what they need in a module. In this example, we are only importing Component
and NgModule
annotations from angular2/core
library and platformBrowserDynamic
method from angular/platform-browser-dynamic
modules. Note that the extension is optional in the definition.
Using platformBrowserDynamic().bootstrapModule
method from angular2 browser module (similar to angular.bootstrap
in Angular1), we can bootstrap the NgModule named MyAppModule
. Angular2 is a lot different from Angular1 on the architectural level. Angular1 only targeted Desktop and Mobile web browsers, but Angular2 is platform agnostic, that means it can be used to write Native mobile apps using NativeScript or Cordova, run angular2 application inside web workers, and to enable server-side rendering with NodeJS or so. For now, we’ll just run it in a web browser by pulling down browser specific bootstrap method as above.
Annotation
The strange-looking syntax above the class called as a Class Decorator that annotates and modifies classes and properties at design time. Wolksoftware’s engineering blog has great articles on decorators and metadata in Typescript. In a nutshell, Angular2 uses decorators/annotations to make dependency injection possible. To simplify it, let us take a small requirement.
Imagine you want to log a function name and passed arguments to browser console every time a method invoked without modifying the function body. In the following example, @debug
is a method decorator that attached a special behavior to the method body. overtime a method called, the decorator will find a method name being called and it’s parameter that we can log. Here is a working demo if interested.
<br>
export class AnnotationExample {<br>
@debug<br>
life(n: number) {<br>
return n;<br>
}<br>
}</p>
<p>function debug(target: Function, fnName: string, fn: any) {<br>
return {<br>
value: function (argument: number) {<br>
document.getElementsByTagName('body')[0].textContent = `function "${fnName}" was called with argument "${argument}"`;<br>
}<br>
};<br>
}</p>
<p>var whatIs = new AnnotationExample();<br>
whatIs.life(42);<br>
On the same note, @component
annotation/decorator tells Angular2 that the defined class, MyApp
is an Angular2 Component not just a ES6 class. And once it’s defined as the component, Angular2 needs to know how the component supposed to be consumed in HTML or which template to render once it’s registered. That’s why we need to pass the meta data as above such as selector, template, etc.
Notice selector name need not be the same as the class name unlike Angular1. There is no restrict
option anymore, instead use a tag name (ng-app) or a property name (with square brackets [ng-app]) or a class name (.ng-app) directly as a selector (I think a comment selector is dropped..!). Also note that we have used a double curly notation for data binding here as there is no ngBind directive available, but you can use property binding (which we’ll explore in future posts) to get the same feeling with <span>Hello, <span [textContent]="name"></span></span>
.
Now let us update HTML markup.
<br>
<html><br>
<head><br>
<title>HTML/DOM Template in Angular2</title><br>
<meta charset="UTF-8"><br>
<meta name="viewport" content="width=device-width, initial-scale=1"></p>
<p> <!-- 1. Load libraries --><br>
<script src="../node_modules/core-js/client/shim.min.js"></script><br>
<script src="../node_modules/zone.js/dist/zone.js"></script><br>
<script src="../node_modules/reflect-metadata/Reflect.js"></script><br>
<script src="../node_modules/systemjs/dist/system.src.js"></script></p>
<p> <!-- 2. Configure SystemJS --><br>
<script src="../systemjs.config.js"></script><br>
<script><br>
System.import('ch01/angular-template').catch(function(err){ console.error(err); });<br>
</script><br>
</head><br>
<body><br>
<!-- 3. Display the application --><br>
<ng-app>Loading...</ng-app><br>
</body><br>
</html><br>
If you remember, we’d included just angular.js
in Angular1 template before, however, Angular2 relies on couple of other JavaScript libraries that you need to inject along with it. But things may change eventually, as it’s just a RC release (at the time of writing this article, and who knows we have to just include one file as before).
Refer SystemJS Wiki for more details to suite your needs. And as you guessed already, we have created a custom element in the body at the end to kick it off.
Wrap up
Peek at a demo..!. That’s it guys..! This is the exact flow you’ll always be using to write new components in Angular2. I liked the progress with Angular2 and Typescript, I would recommend to use Visual Studio Code Editor over SublimeText to feel at home. Be hopeful that many of the things we explored would be simplified by the time it reaches 1.0 (stable), I mean 2.0 😉
If you found this article useful in anyway, feel free to
donate me and receive my dilettante painting as a token of appreciation for your donation.
Like this:
Like Loading...