Getting Started With Angular 2 Step by Step: 1 - Your First Component

| Comments

UPDATE (28th April 2017): This tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms Angular 2 to Angular and Angular 1.x to AngularJS which are now the official names of these frameworks.

Earlier this week Lisa Ryrholm and I where at the first ngStockholm meetup helping people get started with Angular 2. We’re going to have yet another workshop next week and I thought to myself… Wouldn’t it be nice if the people coming to the workshop could have a detailed reference about each and one of the exercises in the workshop? Wouldn’t it be cool if these had nice explanations and step by step directions that they could use during the workshop or refer back to later on?

Angular 2 Getting Started

And voilà here it is… are you interested in a step by step introduction to Angular 2? Then let’s get’s started.

Why Should You Care?

The JavaScript and web world has changed a lot since AngularJS was released. Angular 2 takes advantage of all the advances that have happened since then, embraces web standards and does away with a lot of constructs that are now native to JavaScript such as modules, classes or decorators1.

And not only that, it draws on all the teachings of tons of projects carried out by thounds of developers in AngularJS to provide a more consistent and compact developer experience. One with a reduced number of concepts to grasp and an easy-to-learn development model and syntax.

It’s also faster, provides server-side rendering out of the box, is cross-platform, supports legacy browsers, etc, etc.

Angular 2 is the natural path forward for all the AngularJS developers out there and a great choice for those that appreciate an opinionated framework with a sensible set of defaults, focus on modularity and testability.

Is Angular 2 Ready?

Angular 2 is ready indeed! Since the initial publishing of this article Angular 2 has gone from beta, to RC, to final and now it’s in its version 4. It is used not only by numerous companies but even extensively at Google in more than 200 projects including AdWords, GreenTea (Google’s internal CRM system), and Google Fiber.

The Code Samples

You can download the complete code samples for this blog post from this GitHub repo.

Getting Started With Angular 2 and TypeScript

The best way to get started learning Angular 2 and TypeScript is to use the angular cli to bootstrap a new project.

The angular cli is great because it includes everything you need to start writing your Angular 2 application right away: A front-end build pipeline to transpile your TypeScript into JavaScript that can run in the browser, lots of generators to scaffold your app, a web development server that automatically reflects your changes in the browser as you make them and much more. I call that zero-friction learning :).

So start by installing the Angular cli using npm (you’ll need to install node.js and npm in your development machine before you can continue). In your terminal of choice type:

1
PS> npm install -g @angular/cli

Now you are ready to use the Angular cli to create a new project. The command that you use to access the Angular cli is ng. To create a new app type the following:

1
PS> ng new angular-get-started --style scss

This will create a new Angular 2 project from scratch and set it up so that you can use SASS as CSS preprocessor. If you go inside the angular-get-started folder that should have just been created you’ll find a folder structure that will look more or less like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// app source code (and specs)
- src
  - app                 # your app source code (and specs)
  - assets              # static assets like images, etc
  - index.html          # the entry point to your app
  - styles.scss         # the global styles for your app
  - environments        # here you can define different environment configuration (prod, dev, etc)

// dependencies
- node_modules          # the source code of your app's dependencies
- package.json          # the manifest of your app that states all dependencies 

// TypeScript configuration
- tsconfig.json         # TypeScript compiler configuration
- tslint.json           # TypeScript linting configuration

// Testing
- e2e                   # a folder with end to end tests
- karma.conf.js         # karma test runner configuration
- protractor.conf.js  # protractor e2e tests configuration

- .gitignore
- README.md

You can test that everything works as it should by running the development server. Type the following command:

1
PS>  ng serve --open

This should start the development server, open a browser and load your app. You can stop the server any time by typing CTRL-C a couple of times in the terminal. But for the time being just rejoice! You have created your first Angular 2 application!

Index.html The Entry Point for Your App

The index.html is the entry point to your application:

  • it links to your styles and javascript files
  • it provides the HTML markup for your application with the custom <app-root> element.

If you take a sneak peak at the index.html file in your project you’ll see the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>AngularGetStarted</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <!-- 3. Display the application -->
  <!-- this is your application root component -->
  <app-root>Loading...</app-root>
</body>
</html>

You may be wondering… Hmm… where are the styles and javascript files? All I can see is a custom element app-root. You’ll be happy to know that you don’t have any sight problems as the styles and javascript files are indeed not there… yet. The reason why that is the case is that the angular cli relies on Webpack to inject these files when they are needed.

Bootstrapping Your App

In AngularJS we used the ng-app directive to point Angular 2 to the starting point of your application. In Angular 2 we use a bootstrapper. You can find the bootstrapping logic in the src/main.ts module:

1
2
3
4
5
6
7
8
9
10
11
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);

In this file we import the platformBrowserDynamic object from the '@angular/platform-browser-dynamic' module and call its bootstrapModule function with the AppModule as argument.

There’s two interesting things to note here:

  • The '@angular/platform-browser-dynamic' bootstrapper hints at the fact that Angular 2 is platform agnostic. That is, you can run it in the browser, but you can also run it on a web worker or in the server using different bootstrappers.
  • Notice how we import modules in a different way, Angular 2 modules are imported by name, and application components are imported using relative paths.

Calling the bootstrapModule function with the AppModule as argument tells Angular that this module is the main module for your application.

Wait… But What is an Angular 2 Module? I Thought We Were Just Using ES6 Modules in Angular 2!

Yes, we do use standard ES6 modules in Angular 2. Angular modules are just a new convenience for us developers, a higher level module to wrap ES6 modules that are all about developer ergonomics.

Angular 2 modules and the new NgModule decorator let us declare in one place all the dependencies and components of our application without the need to do it on a per-component basis (like we used to do in previous versions):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [ AppComponent ],
  imports: [ BrowserModule, FormsModule, HttpModule ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

The NgModule decorator takes an object with the following information:

  • an imports array where you declare your module dependencies, for instance, browser, forms, routing or http. The BrowserModule used above contains all the dependencies necessary to run Angular 2 on a browser.
  • a declarations array where you declare the components and directives that belong to the current module.
  • a bootstrap array that identifies the root component that Angular 2 should use to bootstrap your application.

In this example we import an AppComponent component from the app.component.ts module and set it as the root of our application.

But What is a Component?

The component is the core building block of Angular 2 applications. It represents a reusable piece of UI that is usually depicted by a custom html element.

A component is self contained and is constituted by at least a piece of html code that is known as template, a class that encapsulates the data and interactions available to that template, and the aforementioned html element also known selector.

The AppComponent looks like this:

1
2
3
4
5
6
7
8
9
10
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'app works!';
}

It has an AppComponent class that is decorated by some metadata in the form a TypeScript decorator @Component which binds the class to its template, its styles and the app-root selector (Can you remember the <app-root> element from the index.html file?).

This metadata tells Angular 2 that whenever you see an <app-root> html element you should render the template in templateUrl, with the styles in stylesUrls and in the context of the AppComponent class.

If we take a sneak peek at the template you’ll see the following:

1
2
3
<h1>
  {{title}}
</h1>

The title bit (which we call interpolation syntax) tells Angular 2 to display the content of the component title variable when rendering the component. Indeed, if you run ng serve you can see how the browser renders the text app works! inside an h1 element.

If you take a look back at the AppComponent definition and at your project structure you’ll realize that the angular cli follows a convention when creating components:

  • All files for a given component are placed within the same folder named like the component itself (in this case app)
  • These files are named with app.component and have different extensions based on their function:
    • app.component.ts for the component itself
    • app.component.html for the template
    • app.component.scss for the styles

Now let’s do a quick test to see how we can bind the AppComponent class members to the template. Let’s change the title property value from app works! to Star Wars PPlz!!!!!. If you now save the file, your browser should automagically refresh itself and you should be able to see the Star Wars PPlz!!! as the title of your app (If you closed your browser just open it again and if you stopped the development server then remember to run ng serve --open to start it again and see your changes).

Your First Component, Listing Star Wars People Of Note!

Lisa and I were discussing for a while which super duper cool service we would use for our workshop… Spotify, SoundCloud, instagram… and all of the sudden we came to this free and open Star Wars service. So that’s what we’re going to be building, a gateway into the Star Wars universe. Starting with its peoples of note!

The first thing that we are going to do is not going to require services, not yet. We are going to create our first component to display a list of Star Wars people and we will start faking out that data.

It’s good practice to start by defining the domain model of our problem space, in this case a Person. We’ll take advantage of TypeScript interface (although we could’ve used a class as well) and create a Person within the person.ts file. But we won’t create it by hand, we will use the angular cli! Angular cli to the rescue!

The Angular cli has something that we call generators that let you scaffold parts of your application for you. For instance, you can use the following command to create an interface:

1
2
3
PS> ng generate interface person
# or in short-hand:
# ng g i person 

The result of running this command is a person.ts file in your app folder:

1
2
export interface Person{
}

Now let’s add some properties that are representative of a person:

1
2
3
4
5
export interface Person{
    name: string;
    weight: number;
    height: number;
}

Now that we have defined the core object of our domain model let’s create our very first component: the PeopleListComponent. Againt we take advantage of the Angular cli and type the following:

1
2
3
PS> ng generate component --inline-template people-list
# or in short-hand:
# ng g c -it people-list 

This will generate a new folder people-list and will place a TypeScript and a style files within that folder. Since we have selected the --inline-template option, instead of using an external template file the component will use the template property inside the @Component decorator to define an inline template.

It will look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-people-list',
  template: `
    <p>
      people-list Works!
    </p>
  `,
  styleUrls: ['./people-list.component.scss']
})
export class PeopleListComponent implements OnInit {

  // you can ignore these for the time being :)
  constructor() {}
  ngOnInit() {}
}

Ok, now we’ve got a component that we can render using the <app-people-list> element. Indeed, you can appreciate how the Angular cli creates a dummy template so you can test that the component works right away. But we still need to do some changes before we can display a list of Star Wars celebrities.

The next thing that we’ll do is to expose a people property with an array of Person with the mighty Luke, Darth Vader and Solo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Component, OnInit } from '@angular/core';
import { Person } from '../person';

@Component({
  selector: 'app-people-list',
  template: `
    <p>
      people-list Works!
    </p>
  `,
  styleUrls: ['./people-list.component.scss']
})
export class PeopleListComponent{
  people: Person[] = [
    {name: 'Luke Skywalker', height: 177, weight: 70},
    {name: 'Darth Vader', height: 200, weight: 100},
    {name: 'Han Solo', height: 185, weight: 85},
  ];

  constructor(){}
  ngOnInit(){}
}

And now we’ll update its template so that we can represent a list of star wars people. Just like ng-repeat in AngularJS, Angular 2 provides a repeater directive that let’s us repeat a part of a template: *ngFor:

1
2
3
4
5
6
  <!-- this is the new syntax for ng-repeat -->
  <ul>
    <li *ngFor="let person of people">
      {{person.name}}
    </li>
  </ul>

The * before the ngFor denotes the fact that *ngFor is what is called a structural directive, a directive that is going to affect the DOM in some way adding or removing elements to it. Soon you’ll notice how Angular 2 uses a lot of these cues in their syntax to convey a specific meaning and help you learn and understand what the different directives and parts of the framework do.

The let person creates a local template variable that contains each item within the people array and is bound to each li element.

Putting everything together we get:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component, ngOnInit } from '@angular/core';
import { Person } from '../person';

@Component({
  selector: 'app-people-list',
  template: `
  <!-- this is the new syntax for ng-repeat -->
  <ul>
    <li *ngFor="let person of people">
     {{person.name}}
    </li>
  </ul>
  `
})
export class PeopleListComponent{
  people: Person[] = [
    {name: 'Luke Skywalker', height: 177, weight: 70},
    {name: 'Darth Vader', height: 200, weight: 100},
    {name: 'Han Solo', height: 185, weight: 85},
  ];

  constructor(){}
  ngOnInit(){}

}

Now we can update our AppComponent to display the list of StarWars people. We only need to update the app.component.html template:

1
2
<h1>{{title}}</h1>
<app-people-list></app-people-list>

And voilà!!!!! It automagically works! (again check the browser for an update or run ng serve -o).

Once thing that is interesting to mention is that if you had followed the previous steps but you had created the new component with your bare hands it would not have worked. Why is that? That’s because the Angular cli does a lot of things for you in the background. For instance, when we created the component before, the cli not only created the component itself but it also wired it up so we could use it in our application.

Indeed, in order to be able to use a component within another component you need to make your application aware of it. You can do that in the app.module.ts file, that is, in your Angular 2 module. If you take a look at this file you’ll discover the following:

1
2
3
4
5
6
7
8
9
10
11
12
import { AppComponent } from './app.component';
// who did this?
import { PeopleListComponent } from './people-list/people-list.component';

@NgModule({
  declarations: [
    AppComponent,
    PeopleListComponent // and this??
  ],
  // etc...
})
export class AppModule { }

Exactly! The angular cli has wired it up for you and saves you the need from remembering to do it yourself. Magnificent! Thor bless the angular cli!

Concluding

Good job! You’ve started your path to learning Angular 2! Yey! We touched a ton of stuff in this blog post, Angular, TypeScript, the Angular cli, modules, Webpack, bootstrapping, components, decorators, classes and template strings. Wow!

Up next! Refactoring to services!

And if you are interested in getting started with Angular 2, don’t miss our next workshop next week!!!


  1. Decorators are a proposal level 1 still but they are available with Babel and within TypeScript.

Comments