With the final version of Angular 2 just been released last month after the Release Candidate was released in May this year, we decided to get into it at our next project in my company and I decided to save some notes to myself in my blog as usual.
First of: Angular’s official Quick start guide.
TypeScript?
There are many changes in Angular2 compared with Angular1, one of those is the native possibility to use TypeScript, ES2015, Dart or plain javascript to code your app and transpile that later by just using Angular’s config file to set so. This is part of the demo’s config file at Angular’s website where you can see how TypeScript has been configured to write the app:
(function (global) { System.config({ // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER <strong>transpiler: 'ts', typescriptOptions: { tsconfig: true</strong> }, meta: { <strong>'typescript': { "exports": "ts" }</strong> }, paths: { ... }, map: { ... '<strong>ts': 'npm:[email protected]/lib/plugin.js', 'typescript': 'npm:[email protected]/lib/typescript.js',</strong> }, packages: { ... } }); })(this);
As I’m already used to TypeScript and have been developing Angular 1 apps with it, this just makes it easier, so I will continue my post using TS instead than plain JS to work with Angular.
Modules
While we already had modules in Angular1 we are meant to make a much better use of them in here, it’s too soon for me to really know what that means but so far this is how you declare, at least, the main module:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
Note I’m using TypeScript syntax here!
The interesting part of this is how we first include the files we’ll need to declare the module, like NgModule which is a decorator allowing us to declare our module. We also set the dependencies of our module, in this example BrowserModule, declarations, where you declare the components the Module has (more of this later) so it knows what to look for, and the bootstrap directive to tell what to start-up on first load.
Doesn’t look hard though as a first thought I find a bit annoying the idea of registering components in such way instead of self-declaring themselves so they take care of themselves and you don’t need to come back here when creating or removing a component. Though there may be a way to achieve that.
Some Angular 2 common modules when doing a website
- NgModule (inside angular-core)
- Component (also inside angular-core)
- BrowserModule
- FormsModule
- RouterModule
- HttpModule
Components
This is what we called directives in Angular1.
import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: '<h1>My First Angular App</h1>' }) export class AppComponent { }
Note I’m using TypeScript syntax here!
A simple Component declaration, also taken from Angular’s demo, uses a very similar approach as the module. We import required libs, then use the @Component builder (imported with Component inside angular-core) and set its properties, in this basic example just a short template and its “name” now called selector which is the way we add the component to the page. So this component would be inserted as <my-app></my-app>.
Note that we also have the templateUrl property to set a url to a bigger template instead like with Angular 1;
And finally, do not forget that the export keyword is making this component public so that when we import this file from somewhere else that name can be used to reference it. Like Component inside angular-core, as it’s an exportable (and here imported) class. Just in case, let me note a class is not a Component unless we define it as such, so an exported class can be a Component, a Module or whatever we make it.
Angular 2 transcoding
While most of the direct transcoding we had in Angular1 remains in Angular 2 (like {{ 1 +1 }} or {{ person.name }}), Angular1 directives and event binders have changed now. Let’s see some examples taking some code from Angular2 official website:
<li>{{hero.name}}</li> <li (click)="selectHero(hero)"></li> <hero-detail [hero]="selectedHero"></hero-detail> <img [src]='person.imageUrl' />
- First of all, hero.name continues being the same.
- Instead, events like click have now moved from things like ng-click to click inside a parenthesis.
- Properties like ng-src or directives passed-in-values are now in brackets [], like the hero details passed though the [hero] parameter.
The reason for doing this has to do with which way the data should go, which eases the framework’s responsibilities and reduces the amount of used resources. So parenthesis-binded values will go from the view to the controller, in the (click) example, on clicking the element the view will call the controller. The brackets one instead goes from the controller to the DOM (or to the child component).
Two-way data binding
The one-way data bindings take us to the two-way data binding, usually used in forms where we want to pre-load the form with some data and at the same time take user changes over it, so data changes in two-ways (from the component and from the user). In such case we’ll use the double binding using both parenthesis and brackets:
<input [(ngModel)]="hero.name">
Angular 2 directives
While I just said directives are now components, that’s not 100% true, components are actually directives, but to differentiate templated-based directives from non-template based directives they decided to call those others Components and use a decorator with the template properties to make that clear. There are then two other types of directives according to Angular’s official page: structural and attribute directives.
Structural directives
Structural directives alter layout by adding, removing, and replacing elements in DOM.
For example, our loved ng-repeat or ng-if would fall into this category, and by the way, they are now *ngFor and *ngIf:
<li><strong>*ngFor="let hero of heroes"</strong>></li> <hero-detail <strong>*ngIf="selectedHero"</strong>></hero-detail>
Do notice that they use an asterisc and that the ngFor uses of instead than in.
Why of instead than in?
In ES 2015 there are two fors: for…of and for…in. ForOf is used to iterate child objects inside the object while forIn is used to iterate properties. So to keep consistency with ES’15 they decided to use of instead than in.
Attribute directives
Attribute directives alter the appearance or behavior of an existing element. In templates they look like regular HTML attributes, hence the name.
In this category we would have directives like ngStyle, ngClass, ngSwitch or ngModel, the one used to bind form elements in a double-way:
<input [(ngModel)]="hero.name"> <div [ngClass]="setClasses()">This div is saveable and special</div>
Angular 2 Services
Contrary to Angular1 in which we had Services, Factories and even Providers; Angular2 doesn’t provide any of that. But it expects you to use it! How? Well, that’s the point of using TypeScript or EcmaScript’15, that you have classes, which can be exported as services natively so you don’t need the framework to handle that for you.
This is an example of a service done using TypeScript (again, taken from Angular2 website):
export class HeroService { private heroes: Hero[] = []; constructor( private backend: BackendService, private logger: Logger) { } getHeroes() { this.backend.getAll(Hero).then( (heroes: Hero[]) => { this.logger.log(`Fetched ${heroes.length} heroes.`); this.heroes.push(...heroes); // fill cache }); return this.heroes; } }
As you may already know, the constructor keyword is part of the TypeScript language, and the rest is quite self-explanatory, we export a class named HeroService with a public method to retrieve heroes. Note it’s missing the imports to simplify.
As that can be done using TypeScript, there is no need for Angular to provide a framework to handle services, which reduces the size of it and consumed resources.
Injecting the service into the Component
As well as in Angular1, we inject dependencies using dependency injection.
constructor(private service: HeroService) { }
Before injecting a dependency, we must tell Angular which class to use when a dependency is called, for that we use the providers so they tell the framework which one must be called. We can set the provider at the app’s root:
providers: [ BackendService, HeroService, Logger ], </code> Or at the Component itself: <code> @Component({ moduleId: module.id, selector: 'hero-list', templateUrl: 'hero-list.component.html', <strong>providers: [ HeroService ]</strong> })
Further reading
To get more deep into Angular, just follow these links: