This post is part of a series of posts about Angular2. You can find them all in the introduction: https://julienrenaux.fr/2015/11/30/angular2-series-introduction/
Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.
Component
A component is what you used to call a directive in AngularJS. It contains a template, styles, a list of injectables (directives, services) and a selector.
Let’s create a component that lists the US Democratic Party presidential candidates.
import {Component, View, NgFor} from 'angular2/core';
@Component({
selector: "navbar",
directives: [NgFor],
styles: [`
li{
color: gray;
}
`],
template: `
<h2>Democratic Party presidential candidates</h2>
<ul>
<li *ngFor="#item of items; #i = index">{{item}} {{i}}</li>
</ul>
`
})
export class Navbar {
items: Array<String>
constructor() {
this.items = [
"Hillary Clinton",
"Martin O'Malley",
"Bernie Sanders"
]
}
ngOnInit() {
console.log('[Component] navbar ngOnInit');
}
}
When a component is instantiated, Angular2 creates a shadow DOM for the component (Shadow DOM provides encapsulation for the JavaScript, CSS, and templating in a Web Component). Then, the template and styles are injected inside it.
Learn a bit more about Web component and specifically about the <template>
tag by reading the previous article of this series of posts: Angular2 series – Template Syntax.
You can now use your component by inserting it into your html page:
<navbar></navbar>
Demo
http://embed.plnkr.co/cUCWoUDRzd31YRRbo5Rg/preview
Lifecycle hooks
In the previous example, we used the ngOnInit
Class method to dump a message [Component] navbar ngOnInit
in the console. It is called only when the component is initiated. It exists several hooks that make your life easier when it comes to plug yourself in between component life phases.
ngOnChanges
(if any bindings have changed)ngOnInit
(after the first check only)ngOnDestroy
(at the very end before destruction) Implement this interface to get notified when any data-bound property of your directive changesngDoCheck
ngAfterContentInit
ngAfterContentChecked
ngAfterViewInit
ngAfterViewChecked
Directive
Directives allow you to attach behaviour to elements in the DOM. It is also what you used to call a directive in AngularJS, but without a proper view. You can therefore place as many directives as you want on one DOM-element. This is not possible with components.
Let’s get back to our previous component and this time, let’s make our presidential candidates red. To do so, we are going to create the redify
directive:
import {Directive, ElementRef, Renderer} from 'angular2/core';
@Directive({
selector: '[redify]'
})
export class Redify {
constructor(private _element: ElementRef, private renderer: Renderer) {
renderer.setElementStyle(_element, 'color', 'red');
}
}
Notice that in order to obtain a reference to our Presidential Candidate element we injected _element: ElementRef
.
To modify the element style we injected renderer: Renderer
, which is a service that gives you methods to manipulate the style of a particular element.
Then we can add the redify
directive to our component:
import {Redify} from 'path/to/your/Redify/directive';
@Component({
selector: "navbar",
directives: [NgFor, Redify],
...
template: `
<li redify *ngFor="#item of items; #i = index">{{item}} {{i}}</li>
`
})
Result
http://embed.plnkr.co/iJiZVqixM0qAo4RMelB7/preview
Pipe
A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).
A better explanation of what is a pipe is available in the previous article of this series of posts: Angular2 series – Template Syntax
Let’s get back again to our previous component and this time, let’s create a pipe to transform our presidential candidates last name to uppercase.
First we create lastnameUppercase
pipe:
import {Pipe} from 'angular2/core';
@Pipe({
name: 'lastnameUppercase'
})
export class LastnameUppercase {
transform(v, args) {
return `${v.split(' ')[0]} ${v.split(' ')[1].toUpperCase()}`;
}
}
Then let’s add this pipe to our navbar
component in order to consume it.
import {LastnameUppercase} from './pipes';
@Component({
selector: "navbar",
...
pipes: [LastnameUppercase],
template: `
<li redify *ngFor="#item of items; #i = index">{{item | lastnameUppercase}} {{i}}</li>
`
})
Demo
http://embed.plnkr.co/L1ERY1Pn6qmGl0B1hi0K/preview
Built in pipes
In Angular2 you have access to the following pipes for free:
currency
date
uppercase
json
limitTo
lowercase
async
decimal
percent
Service
Now that we saw how to create a component, a directive and a pipe, we are going to clean up our code and separate the data retrieval (the presidential candidates) into a service.
import {Injectable} from 'angular2/core';
@Injectable()
export class PresidentialCandidate {
constructor() {}
getRepublicainList() {
return [
"Donald Trump",
"Rand Paul",
"Ben Carson"
]
}
getDemocraticList() {
return [
"Hillary Clinton",
"Martin O'Malley",
"Bernie Sanders"
]
}
}
Now let’s consume this service on our navbar
component:
import {PresidentialCandidate} from './services';
@Component({
selector: "navbar",
providers: [PresidentialCandidate],
...
template: `
<h2>Democratic Party presidential candidates</h2>
<ul>
<li redify *ngFor="#item of democrats; #i = index">{{item | lastnameUppercase}} {{i}}</li>
</ul>
<h2>Republican Party presidential candidates</h2>
<ul>
<li redify *ngFor="#item of republicans; #i = index">{{item | lastnameUppercase}} {{i}}</li>
</ul>
`
})
export class Navbar {
democrats: Array<String>
republicans: Array<String>
constructor(private presidentialService :PresidentialCandidate) {
this.democrats = presidentialService.getDemocraticList();
this.republicans = presidentialService.getRepublicainList();
}
}
We have decoupled the presidential candidates retrieval with the component that displays them. It is now easier for other components to consume this data.
Demo
http://embed.plnkr.co/z1B96b4OX7BHwkT0492G/preview
Application
AngularJS
With AngularJS an application was a simple module. It had no difference from any other module of your application.
angular.module('yourApp', []);
Angular2
With Angular2, it is similar. An application is a simple component as any other component of your application. It is just the root component that basically contains the scaffolding of your page.
@Component({
selector: "yourApp"
})
@View({
directives: [Header, Navbar, Content, Footer]
template: `
<header></header>
<navbar></navbar>
<content></content>
<footer></footer>
`
})
export class App {
constructor() {
}
}
Header
, Navbar
, Content
and Footer
are custom components, they do not exist within Angular2 core.
Bootstrap
Now that you know how to create components and a root component (or app), you need to bootstrap the application.
AngularJS
In AngularJS you could use angular.bootstrap(document, ['yourApp']);
or the ng-app
directive <body ng-app="yourApp">
.
Angular2
In Angular2 it is very similar.
import {bootstrap} from 'angular2/core';
import {yourApp} from 'path/to/your/app/component';
bootstrap(yourApp, []);
Our application is now ready to be rendered. Insert your app component in your index.html
file and reload the browser, your app is ready!
<body>
<app>
Loading...
</app>
</body>
Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook!