In this article, we are going to take a tour around a simple Angular 2 website and get acquainted with Angular components and how they work. Under the hood of most Angular 2 mechanisms is a vanilla ES6 class, with Angular using metadata to enhance the class with all its powers. We will use component metadata to tell Angular how the class is supposed to behave.
This article will focus on just the essentials. Check out the repository at and the accompanying screencast for a treasure trove of extra tips and techniques.
The root component
The single most important theme in Angular 2 is components. These are the basic building blocks that everything else is built upon. As a result, the genesis of every Angular 2 application is its ‘root’ component. In the body of our main HTML file we start with a single app element that is the entry point for our application. Everything inside this tag is visible until Angular is bootstrapped.
// index.html <body> <app>Loading…</app> </body>
To bootstrap the app, we import the bootstrap method from the platform-browser-dynamic package. We also import the root component. Then we call the bootstrap method, passing in the root component and an array of providers.
// boot.ts import {bootstrap} from ‘@angular/platform-browserdynamic’; import {AppComponent} from ‘./app.component’; bootstrap(AppComponent, []);
To create a component, create a TypeScript class called AppComponent to represent the component, and then import the Component class from the Angular core. Finally, decorate the class by adding @Component metadata and passing a configuration object to it.
You can enhance your component by augmenting the config object with properties such as selector (the HTML tag representing the component), template and styles. You can also specify an array of providers (services, for example) and directives. In a moment we are going to repeat this same process when we create a child component.
Note that in Angular 2, it is considered best practice to favour fine-grained components with a single, specific task. A rule of thumb is that you have accomplished this when your HTML is small enough to be inlined within the decorator without being cumbersome.
// app.component.ts import {Component} from ‘@angular/core’; @Component({ selector: ‘app’, styles: [ h1 { text-align: center; } ], template: <h1>Hello Angular 2!</h1> }) export class AppComponent {}
You’ll find a working example in the ‘01-gettingstarted’ branch of the GitHub repository.
Child components
Let’s create a home component. The first thing we are going to do is create our HomeComponent class and set the title and body properties. We will also import Component from @angular/core so we can use it to decorate our new class in just a moment.
// home.component.ts import {Component} from ‘@angular/core’; export class HomeComponent { title: string = ‘Home Page’; body: string = ‘This is the about home body’; }
We are going to enhance our Component metadata with the selector we want to use to target our component, the path to the HTML template and some CSS for aesthetic purposes.
// home.component.ts import {Component} from ‘@angular/core’; @Component({ selector: ‘home’, template: require(‘./home.component.html’), styles: [ .content-card > .mdl-card__title { color: #fff; height: 176px; background: url(‘../images/home-card.jpg’) center / cover; } ] }) export class HomeComponent { title: string = ‘Home Page’; body: string = ‘This is the about home body’; }
We can bind to any public properties or methods in our TypeScript class, so in our home.component.html file we are going to use curly brace string interpolation to render our title and body values.
// home.component.html <div class=”content-card”> <div class=”mdl-card__title”> <h1>{{ title }}</h1> </div> <div> {{ body }} </div> </div>
We can repeat this process for an ItemsComponent and AboutComponent and then make all three of our newly minted child components available to the AppComponent by importing them and injecting them in via the directives array on the class metadata.
// app.component.ts import {Component} from ‘@angular/core’; import {AboutComponent} from ‘./about/about.component’; import {ItemsComponent} from ‘./items/items.component.ts’; import {HomeComponent} from ‘./home/home.component’; @Component({ selector: 'app', template: require('./app.component.html'), styles: [require('./app.component.css')], directives: [HomeComponent, AboutComponent, ItemsComponent] }) export class AppComponent {}
Angular 2 components by nature are self-contained, so when we want to render them on the page, we just need to add our component selectors to the markup as you can see below. The pleasant side effect of this component-driven architecture is that our HTML is now a DSL and very descriptive of the domain model we are working in.
// app.component.html <main> <div> <home></home> <about></about> <items></items> </div> </main>
If you check out the ‘02-components’ branch of the repository, you will see a working example of this.
Routing
Creating a bunch of components and dumping them on a page is interesting but not necessarily reflective of how we build apps in real life. We need to be able to navigate between components as if they were pages in a website, and we can use the ComponentRouter to accomplish this task.
We are going to update our boot.ts file slightly by importing the ROUTER_PROVIDERS from the Angular router package. We will then insert ROUTER_PROVIDERS into our providers array in the bootstrap method call.
// boot.ts import {bootstrap} from ‘@angular/platform-browserdynamic’; import {ROUTER_PROVIDERS} from ‘@angular/router’; import {AppComponent} from ‘./app.component’; bootstrap(AppComponent, [ ROUTER_PROVIDERS ]);
Because this is a small application, we are going to configure our routes in the root component. We will start by importing the Routes decorator and the ROUTER_DIRECTIVES from Angular’s router package. We need the ROUTER_DIRECTIVES if we want to create links to our routes in our HTML.
//app.component.ts import {Component} from ‘@angular/core’; import {Routes, ROUTER_DIRECTIVES} from ‘@angular/ router’; import {AboutComponent} from ‘./about/about.component’; import {ItemsComponent} from ‘./items/items.component.ts’; import {HomeComponent} from ‘./home/home.component’; @Component({ selector: ‘app’, template: require(‘./app.component.html’), styles: [require(‘./app.component.css’)], directives: [ROUTER_DIRECTIVES] }) @Routes([ {path: ‘/’, component: HomeComponent}, {path: ‘/home’, component: HomeComponent}, {path: ‘/about’, component: AboutComponent}, {path: ‘/items’, component: ItemsComponent}, {path: ‘/*’, component: HomeComponent} ]) export class AppComponent {}
We will then decorate our AppComponent with some additional @Routes metadata that contains the routing table for our application. A basic route is an object that consists of a path and the component that the path links to.
Did you notice the ‘/’ and ‘/*’ routes? The former matches the root URL of the application (http://example.com) and serves the HomeComponent, while the latter matches any unregistered URLs and serves HomeComponent.
Now that our routes are configured, we can update our templates to link to specific routes. To link to a registered route in the component HTML, we will place a [routerLink] attribute on an anchor tag.
The value should be an array of paths. In this case, since we don’t have any extra parameters, we just need one path (which we specified in the @Routes decoration).
// app.component.html <header> <div> <nav> <a [routerLink]=”[‘/home’]”>HOME</a> <a [routerLink]=”[‘/about’]”>ABOUT</a> <a [routerLink]=”[‘/items’]”>ITEMS</a> </nav> </div> </header> <main> <div> <router-outlet></router-outlet> </div> </main>
If you check out the ‘03-routes’ branch of the repository, you’ll see our routing table in action.
In closing
All complex systems are just composed of a bunch of smaller systems that work together to produce something impressive. Angular 2 is incredibly powerful, and because of that it can seem like we are standing at the foot of a cliff trying to figure out how we are going to get to the top.
The process becomes far less daunting when we realise we are just working with components that can be stamped out using the simple process of creating the class, importing our dependencies, decorating our class, enhancing our component and repeating from the beginning.