QuickStart

Step 1. Set up the Development Environment

1
2
$ yaourt -S nodejs npm
$ npm install -g @angular/cli

Step 2. Create a new project

1
$ ng new my-app

Step 3: Serve the application

1
2
$ cd my-app
$ ng serve --open

Step 4: Edit your first Angular component

1
2
3
4
# ./src/app/app.component.ts
export class AppComponent {
  title = 'My First Angular App!';
}
1
2
3
4
5
6
# ./src/app/app.component.css
h1 {
  color: #369;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 250%;
}

Project file review

 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
my-app
    e2e                   # end-to-end tests
        src
            app.e2e-spec.ts
            app.po.ts
        tsconfig.e2e.json
        protractor.conf.js            # test configuration, used when running ng e2e.
    node_modules/...                  # all third party modules listed in package.json
    src
    	app                           # It is the root component 
            app.component.css
            app.component.html         # the component template file
            app.component.spec.ts
            app.component.ts           # the component class file
            app.module.ts              # it declares components
        assets                         # put images and anything else to here
        	.gitkeep
        environments               # Production, Test & Development Environments
            environment.prod.ts
            environment.ts
        browserslist               # A configuration file to share target browsers 
        favicon.ico                 # bookmark bar icon
        index.html                  # Most of the time you'll never need to edit it. 
        karma.conf.js              # Unit test configuration for the Karma test runner.
        main.ts                      # main entry point
        polyfills.ts                  # normalize the differences between browsers
        styles.css                     # global styles
        test.ts                      # the main entry point for your unit tests
        tsconfig.app.json            # compiler configuration the Angular app 
        tsconfig.spec.json           # compiler configuration for the unit tests 
        tslint.json                # used when running ng lint. 
    	karma.conf.js
    .editorconfig                  # configuration for the editor 
    .gitignore
    angular.json                  # Configuration for Angular CLI. 
    package.json                 # listing the third party packages
    README.md
    tsconfig.json               # compiler configuration for your IDE
    tslint.json                   # keep your code style when running ng lint.

Tutorial

1
2
3
4
$ npm install -g @angular/cli
$ ng new angular-tour-of-heroes
$ cd angular-tour-of-heroes
$ ng serve --open

Angular components

Components are the fundamental building blocks of Angular applications. They display data on the screen, listen for user input, and take action based on that input.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# src/app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Tour of Heroes';
}

Create a new component

create a new component to display hero information and place that component in the application shell.

1
$ ng generate component heroes
1
2
3
4
5
# src/app/heros.ts
export class Hero {
  id: number;
  name: string;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# src/app/heros/heros.component.ts
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
  hero: Hero = {
    id: 1,
    name: 'Windstorm'
  };

  constructor() { }

  ngOnInit() {
  }

}

@Component is a decorator function that specifies the Angular metadata for the component. The metadata properties selector is the component’s CSS element selector.

The CSS element selector, 'app-heroes', matches the name of the HTML element that identifies this component within a parent component’s template.

The ngOnInit is a lifecycle hook Angular calls ngOnInit shortly after creating a component. It’s a good place to put initialization logic.

Always export the component class so you can import it elsewhere … like in the AppModule.

1
2
3
# src/app/app.component.html
<h1>{{title}}</h1>
<app-heroes></app-heroes>

The double curly braces are Angular’s interpolation binding syntax. Remember that app-heroes is the element selector for the HeroesComponent. So add an <app-heroes> element to the AppComponent template file

1
2
3
4
5
6
7
8
# src/app/heros/heros.component.html
<h2>{{ hero.name | uppercase }} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>
    <label>name:
      <input [(ngModel)]="hero.name" placeholder="name">
    </label>
</div>

The word uppercase in the interpolation binding, right after the pipe operator ( | ), activates the built-in UppercasePipe.

[(ngModel)] is Angular’s two-way data binding syntax.

Here it binds the hero.name property to the HTML textbox so that data can flow in both directions: from the hero.name property to the textbox, and from the textbox back to the hero.name.

Although ngModel is a valid Angular directive, it isn’t available by default. It belongs to the optional FormsModule and you must opt-in to using it.

AppModule

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; // <-- NgModel lives here

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

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

Some of the metadata is in the @Component decorators that you added to your component classes. Other critical metadata is in @NgModule decorators.

The @NgModule metadata’s imports array contains a list of external modules that the app needs.

Every component must be declared in exactly one NgModule. Note that AppModule declares both application components, AppComponent and HeroesComponent.

Display a Heroes List

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# src/app/heros/heros.component.ts
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

  heroes = HEROES;
  selectedHero: Hero;

  constructor() { }

  ngOnInit() {
  }
  
  onSelect(hero: Hero): void {
    this.selectedHero = hero;
  }
}

Add the click event handler.

Class binding

Event binding ( (event) )

Hide empty details with *ngIf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# src/app/heros/heros.component.html
<h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>
 
<div *ngIf="selectedHero">
 
  <h2>{{ selectedHero.name | uppercase }} Details</h2>
  <div><span>id: </span>{{selectedHero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="selectedHero.name" placeholder="name">
    </label>
  </div>
 
</div>

The *ngFor is Angular’s repeater directive. It repeats the host element for each element in a list.

Class binding syntax start with the prefix class, optionally followed by a dot (.) and the name of a CSS class: [class.class-name]. The Angular class binding makes it easy to add and remove a CSS class conditionally. Just add [class.some-css-class]="some-condition" to the element you want to style.

The parentheses around click tell Angular to listen for the <li> element’s click event. When the user clicks in the <li>, Angular executes the onSelect(hero) expression.

onSelect() is a HeroesComponent method that you’re about to write. 

After the browser refreshes, the list of names reappears. The details area is blank because of *ngIf will be false. Click a hero and its details appear.

1
2
# src/app/heros/heros.component.css
/* HeroesComponent's private CSS styles */

Master/Detail Components

Keeping all features in one component as the application grows will not be maintainable. You’ll want to split up large components into smaller sub-components, each focused on a specific task or workflow.

1
$ ng generate component hero-detail

Add the @Input() hero property

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# src/app/hero-detail/hero-detail.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { Hero } from '../hero';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {
  @Input() hero: Hero;

  constructor() { }

  ngOnInit() {
  }

}

The hero property must be an Input property, annotated with the @Input() decorator, because the external HeroesComponent will bind to it

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# src/app/hero-detail/hero-detail.component.html
<div *ngIf="hero">

  <h2>{{ hero.name | uppercase }} Details</h2>
  <div><span>id: </span>{{hero.id}}</div>
  <div>
    <label>name:
      <input [(ngModel)]="hero.name" placeholder="name"/>
    </label>
  </div>

</div>

property binding

The two components will have a parent/child relationship. The parent HeroesComponentwill control the child HeroDetailComponent by sending it a new hero to display whenever the user selects a hero from the list.

You won’t change the HeroesComponent class but you will change its template.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# src/app/heros/heros.component.html
<h2>My Heroes</h2>

<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>

[hero]="selectedHero" is an Angular property binding.

It’s a one way data binding from the selectedHero property of the HeroesComponent to the hero property of the target element, which maps to the hero property of the HeroDetailComponent.

Now when the user clicks a hero in the list, the selectedHero changes. When the selectedHero changes, the property binding updates hero and the HeroDetailComponentdisplays the new hero.

Services

Services are a great way to share information among classes that don’t know each other

Create the HeroService

1
$ ng generate service hero

Annotates the class with the @Injectable() decorator. This marks the class as one that participates in the dependency injection system

The @Injectable() decorator accepts a metadata object for the service, the same way the @Component() decorator did for your component classes.

The HeroService could get hero data from anywhere—a web service, local storage, or a mock data source.

Provide the HeroService

You must make the HeroService available to the dependency injection system before Angular can inject it into the HeroesComponent. You do this by registering a provider. A provider is something that can create or deliver a service; in this case, it instantiates the HeroService class to provide the service.

By default, the Angular CLI command ng generate service registers a provider with the root injector for your service .

If you need to, you can register providers at different levels: in the HeroesComponent, in the AppComponent, in the AppModule. For instance, you could have told the CLI to provide the service at the module level automatically by appending --module=app.

1
$ ng generate service hero --module=app

Observable data

The HeroService must wait for the server to respond, getHeroes() cannot return immediately with hero data, and the browser will not block while the service waits. HeroService.getHeroes() must have an asynchronous signature of some kind. It can take a callback. It could return a Promise. It could return an Observable. HttpClient.get() returns an Observable.

Observable is one of the key classes in the RxJS library.

Angular’s HttpClient methods return RxJS Observables. 

Getting data from the server with the RxJS of() function.

Inject MessageSerice into the HeroService

This is a typical “service-in-service” scenario: you inject the MessageService into the HeroService which is injected into the HeroesComponent.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# src/app/hero.service.ts
import { Injectable } from '@angular/core';
 
import { Observable, of } from 'rxjs';
 
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
import { MessageService } from './message.service';
 
@Injectable({
  providedIn: 'root',
})
export class HeroService {
 
  constructor(private messageService: MessageService) { }
 
  getHeroes(): Observable<Hero[]> {
    // TODO: send the message _after_ fetching the heroes
    this.messageService.add('HeroService: fetched heroes');
    return of(HEROES);
  }
}

Update HeroesComponent

  1. Import the HeroService
  2. Add a private heroService parameter of type HeroService to the constructor. The parameter simultaneously defines a private heroService property and identifies it as a HeroService injection site.
  3. Add getHeroes() , create this function to retrieve the heroes from the service.
  4. Call it in ngOnInit. You could call getHeroes() in the constructor, that’s not the best practice. Reserve the constructor for simple initialization such as wiring constructor parameters to properties. It certainly shouldn’t call a function that makes HTTP requests to a remote server as a real data service would. Let Angular call ngOnInitat an appropriate time after constructing a HeroesComponent instance.
  5. The HeroService.getHeroes method returns an Observable<Hero[]>. The new getHeroes method waits for the Observable to emit the array of heroes. Then subscribe passes the emitted array to the callback, which sets the component’s heroes property.
 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
26
27
28
29
30
31
32
# src/app/heroes/heroes.component.ts 
import { Component, OnInit } from '@angular/core';

import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
 selector: 'app-heroes',
 templateUrl: './heroes.component.html',
 styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

 selectedHero: Hero;

 heroes: Hero[];

 constructor(private heroService: HeroService) { }

 ngOnInit() {
   this.getHeroes();
 }

 onSelect(hero: Hero): void {
   this.selectedHero = hero;
 }

 getHeroes(): void {
   this.heroService.getHeroes()
       .subscribe(heroes => this.heroes = heroes);
 }
}

Create MessagesComponent

1
$ ng generate component messages
1
2
3
4
# /src/app/app.component.html
<h1>{{title}}</h1>
<app-heroes></app-heroes>
<app-messages></app-messages>
Create the MessageService
1
$ ng generate service message
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# /src/app/message.service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class MessageService {
  messages: string[] = [];

  add(message: string) {
    this.messages.push(message);
  }

  clear() {
    this.messages = [];
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# src/app/messages/messages.component.ts
import { Component, OnInit } from '@angular/core';
import { MessageService } from '../message.service';

@Component({
  selector: 'app-messages',
  templateUrl: './messages.component.html',
  styleUrls: ['./messages.component.css']
})
export class MessagesComponent implements OnInit {

  constructor(public messageService: MessageService) {}

  ngOnInit() {
  }

}

The messageService property must be public because you’re about to bind to it in the template. Angular only binds to public component properties.

1
2
3
4
5
6
7
8
9
# src/app/messages/messages.component.html
<div *ngIf="messageService.messages.length">

  <h2>Messages</h2>
  <button class="clear"
          (click)="messageService.clear()">clear</button>
  <div *ngFor='let message of messageService.messages'> {{message}} </div>

</div>

Routing

Add the AppRoutingModule

An Angular best practice is to load and configure the router in a separate.

1
ng generate module app-routing --flat --module=app

--flat puts the file in src/app instead of its own folder. --module=app tells the CLI to register it in the imports array of the AppModule.

The fundamentals of Angular

Class binding

Event binding ( (event) )link

Pipes

Pipes are a good way to format strings, currency amounts, dates and other display data. Angular ships with several built-in pipes and you can create your own.