Angular 2 - Misc2

angular2

// Angular 2 - Misc 2:

import { Hero } from './hero';

To separate the "hero detail" component, add a new file name 
hero-detail.component.ts to the app folder:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'my-hero-detail'
});

export class HeroDetailComponent {
}

We begin by importing the Component and Input decorators from Angular.  We 
create metadata with the @Component decorator where we specify the selector 
name that identifies this component's element. Then we export the class to 
make it available to other components.

We now need to move the "hero detail" part from the app.component.ts file
to the hero-detail.component.ts.

We now relocate the Hero class from app.component.ts to its own hero.ts file:

export class Hero {
  id: number;
  name: string;
}

We then import the Hero class into the app.component.ts file and the 
hero-details.component.ts file:

import { Hero } from './hero';

Previously we used the selectedHero property, but the "hero details" component
might be more generic, so we changed the template to use hero instead of
selectedHero.

The HeroDetailComponent must be told what here to display.  The parent
AppComponent is responsible for this.  The AppComponent knows which hero to
show: the hero that the user selected from the list.  The user's selection is
in its selectedHero property.  We will soon update the AppComponent template
so that it binds its selectedHero property to the hero property of our
HeroDetailComponent.  The binding might look like this:

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

Notice that the hero property is the target of the property binding.  It is in
square brackets to the left of the equal sign.  Angular insists that we declare 
a target property to be an input property. If we don't, Angular rejects the 
binding and throws an error.  There are a couple of ways we can declare that 
hero is an input. We'll do it the way we prefer, by annotating the hero property 
with the @Input decorator that we imported earlier.

@Input()
hero: Hero;

We return to the AppModule, the application's root module, and teach it to use 
the HeroDetailComponent.  We begin by importing the HeroDetailComponent so we 
can refer to it.

import { HeroDetailComponent } from './hero-detail.component';

Then we add HeroDetailComponent to the NgModule decorator's declarations array. 
This array contains the list of all components, pipes, and directives that we 
created and that belong in our application's module.

Now that the application knows about our HeroDetailComponent, find the location 
in the AppComponent template where we removed the Hero Detail content and add an 
element tag that represents the HeroDetailComponent.

<my-hero-detail></my-hero-detail>

my-hero-detail is the name we set as the selector in the HeroDetailComponent 
metadata.  The two components won't coordinate until we bind the selectedHero 
property of the AppComponent to the HeroDetailComponent element's hero property 
like this:

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

Because of this binding, the HeroDetailComponent should receive the hero from 
the AppComponent and display that hero's detail.  The detail should update every 
time the user picks a new hero.

To create the hero "data service", create the hero.service.ts in the app folder:

import { Injectable } from '@angular/core';

@Injectable()
export class HeroService {
}

Notice that we imported the Angular Injectable function and applied that 
function as an @Injectable() decorator.  Do not forget the parentheses! 
Neglecting them leads to an error that's difficult to diagnose.  TypeScript sees 
the @Injectable() decorator and emits metadata about our service, metadata that 
Angular may need to inject other dependencies into this service.

The HeroService doesn't have any dependencies at the moment. Add the decorator 
anyway. It is a "best practice" to apply the @Injectable() decorator ​from the 
start​ both for consistency and for future-proofing.

@Injectable()
export class HeroService {
  getHeroes(): void {} // stub
}

The mock hero data in the app.component.ts file does not belong there, but it 
does not really belong in the hero.service.ts file neither.  Lets put it in a
new file named mock-heroes.ts.  We copy the 'import {Hero} ...' statement as 
well because the heroes array uses the Hero class.

import { Hero } from './hero';
export const HEROES: Hero[] = [
  {id: 11, name: 'Mr. Nice'},
  {id: 12, name: 'Narco'},
  {id: 13, name: 'Bombasto'},
  {id: 14, name: 'Celeritas'},
  {id: 15, name: 'Magneta'},
  {id: 16, name: 'RubberMan'},
  {id: 17, name: 'Dynama'},
  {id: 18, name: 'Dr IQ'},
  {id: 19, name: 'Magma'},
  {id: 20, name: 'Tornado'}
];

We export the HEROES constant so we can import it elsewhere.

Meanwhile, back in app.component.ts where we cut away the HEROES array, we leave 
behind an uninitialized heroes property:

heroes: Hero[];

Back in the HeroService we import the mock HEROES and return it from the 
getHeroes method. Our HeroService looks like this:

import { Injectable } from '@angular/core';

import { Hero } from './hero';
import { HEROES } from './mock-heroes';

@Injectable()
export class HeroService {
  getHeroes(): Hero[] {
    return HEROES;
  }
}

Now we import the thing we want to use, the HeroService.  We could create a new 
instance of the HeroService with new like this:

heroService = new HeroService(); // don't do this

That's a bad idea for several reasons including:

1. Our component has to know how to create a HeroService. If we ever change the 
   HeroService constructor, we'll have to find every place we create the service 
   and fix it. Running around patching code is error prone and adds to the test 
   burden.

2. We create a new service each time we use new. What if the service should 
   cache heroes and share that cache with others? We couldn't do that.

3. We're locking the AppComponent into a specific implementation of the 
   HeroService. It will be hard to switch implementations for different 
   scenarios. Can we operate offline? Will we need different mocked versions 
   under test? Not easy.

To avoid the above issues, we inject the HeroService.  Two lines replace the
one line that created with new:

1. We add a constructor that also defines a private property.
2. We add the component's providers metadata.

Here is the constructor (app.component.ts):

constructor(private heroService: HeroService) { }

The constructor itself does nothing. The parameter simultaneously defines a 
private heroService property and identifies it as a HeroService injection site.
Now Angular will know to supply an instance of the HeroService when it creates 
a new AppComponent

The injector does not know yet how to create a HeroService. If we ran our code 
now, Angular would fail with an error:

EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)

We have to teach the injector how to make a HeroService by registering a 
HeroService provider. Do that by adding the following providers array property 
to the bottom of the component metadata in the @Component call.

providers: [HeroService]

The providers array tells Angular to create a fresh instance of the HeroService 
when it creates a new AppComponent. The AppComponent can use that service to get 
heroes and so can every child component of its component tree.

We've got the service in a heroService private variable. Let's use it.  We can 
call the service and get the data in one line.

this.heroes = this.heroService.getHeroes();

We don't really need a dedicated method to wrap one line. We write it anyway:

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

Years of experience and bitter tears have taught us to keep complex logic out 
of the constructor, especially anything that might call a server as a data 
access method is sure to do.

The constructor is for simple initializations like wiring constructor parameters 
to properties. It's not for heavy lifting. We should be able to create a 
component in a test and not worry that it might do real work — like calling a 
server! — before we tell it to do so.  If not the constructor, something has to 
call getHeroes.

Angular will call it if we implement the Angular ngOnInit Lifecycle Hook. 
Angular offers a number of interfaces for tapping into critical moments in the 
component lifecycle: at creation, after each change, and at its eventual 
destruction.  Each interface has a single method. When the component implements 
that method, Angular calls it at the appropriate time.

Here's the essential outline for the OnInit interface:

app.component.ts (ngOnInit stub):

import { OnInit } from '@angular/core';
export class AppComponent implements OnInit {
  ngOnInit(): void {
  }
}

In the above code, we import OnInit into the app.component.ts file, and we also
modified the AppComponent class to implement the OnInit interface.

We write an ngOnInit method with our initialization logic inside and leave it to 
Angular to call it at the right time. In our case, we initialize by calling 
getHeroes.

ngOnInit(): void {
  this.getHeroes();
}

Update the HeroService with this Promise-returning getHeroes method:

// hero.service.ts (excerpt)
getHeroes(): Promise<Hero[]> {
  return Promise.resolve(HEROES);
}

We're still mocking the data. We're simulating the behavior of an ultra-fast, 
zero-latency server, by returning an immediately resolved Promise with our mock 
heroes as the result.

Now we need to update the getHeroes method in app.component.ts to act on the
promise:

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

getHeroesSlowly(): Promise<Hero[]> {
  return new Promise<Hero[]>(resolve =>
    setTimeout(resolve, 2000)) // delay 2 seconds
    .then(() => this.getHeroes());
}

// Routing:
Routes tell the router which views to display when a user clicks a link or 
pastes a URL into the browser address bar.

To define routes, add to app.module.ts:

import { RouterModule }   from '@angular/router';
RouterModule.forRoot([
  {
    path: 'heroes',
    component: HeroesComponent
  }
])

The routes are an array of route definition.  The route definition has the
following parts:

1. path: the router matches this route's path to the URL in the browser address 
   bar (heroes).

2. component: the component that the router should create when navigating to 
   this route.

Next, we need to make the router available.  To do this, we'll add it to 
AppModule imports array:

import { NgModule }       from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { FormsModule }    from '@angular/forms';
import { RouterModule }   from '@angular/router';

import { AppComponent }        from './app.component';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroesComponent }     from './heroes.component';
import { HeroService }         from './hero.service';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot([
      {
        path: 'heroes',
        component: HeroesComponent
      }
    ])
  ],
  declarations: [
    AppComponent,
    HeroDetailComponent,
    HeroesComponent
  ],
  providers: [
    HeroService
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
}

We use the forRoot method because we're providing a configured router at the 
root of the application. The forRoot method gives us the Router service 
providers and directives needed for routing, and performs the initial navigation 
based on the current browser URL.

// Router Outlet.

If we paste the path, /heroes, into the browser address bar, the router should 
match it to the heroes route and display the HeroesComponent. But where?  We 
have to tell it where by adding a <router-outlet> element to the bottom of the 
template. RouterOutlet is one of the directives provided by the RouterModule. 
The router displays each component immediately below the <router-outlet> as we 
navigate through the application.

We don't really expect users to paste a route URL into the address bar. We add 
an anchor tag to the template which, when clicked, triggers navigation to the 
HeroesComponent.  The revised template looks like this:

// app.component.ts
template: `
   <h1>{{title}}</h1>
   <a routerLink="/heroes">Heroes</a>
   <router-outlet></router-outlet>
 `

Notice the routerLink binding in the anchor tag. We bind the RouterLink 
directive (another of the RouterModule directives) to a string that tells the 
router where to navigate when the user clicks the link.

The AppComponent is now attached to a router and displaying routed views. For 
this reason and to distinguish it from other kinds of components, we call this 
type of component a Router Component.

If we want to redirect the default path (/) to another path:

{
  path: '',
  redirectTo: '/dashboard',
  pathMatch: 'full'
},

If we want to put the template into a file of its own, we need to update
the component file to use the templateUrl property instead of the template
property:

@Component({
  moduleId: module.id,
  selector: 'my-dashboard',
  templateUrl: 'dashboard.component.html',
})

In the above code, we set the moduleId property to module.id for module-relative 
loading of the templateUrl. 

Recall earlier in the chapter that we removed the HeroService from the providers 
array of HeroesComponent and added it to the providers array of AppModule.  That 
move created a singleton HeroService instance, available to all components of 
the application. Angular will inject HeroService and we'll use it here in the 
DashboardComponent.

At this point, we need to update the hero-detail.component.ts (the 
HeroDetailComponent).  We will no longer receive the hero in a parent component 
property binding. The new HeroDetailComponent should take the id parameter from 
the params observable in the ActivatedRoute service and use the HeroService to 
fetch the hero with that id.  First, add the requisite imports:

import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, Params }   from '@angular/router';
import { Location }                 from '@angular/common';

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

Let's have the ActivatedRoute service, the HeroService and the Location service 
injected into the constructor, saving their values in private fields:

constructor(
  private heroService: HeroService,
  private route: ActivatedRoute,
  private location: Location
) {}

We'll also import the switchMap operator to use later with the route parameters 
Observable:

// hero-detail.component.ts
import 'rxjs/add/operator/switchMap';

We tell the class that we want to implement the OnInit interface:

export class HeroDetailComponent implements OnInit { ... }

Inside the ngOnInit lifecycle hook, we use the params observable to extract the 
id parameter value from the ActivatedRoute service and use the HeroService to 
fetch the hero with that id.

ngOnInit(): void {
  this.route.params
    .switchMap((params: Params) => this.heroService.getHero(+params['id']))
    .subscribe(hero => this.hero = hero);
}

Note how the switchMap operator maps the id in the observable route parameters 
to a new Observable, the result of the HeroService.getHero method.

If the user re-navigates to this component while a getHero request is still 
inflight, switchMap cancels that old request before calling HeroService.getHero 
again.

The hero id is a number. Route parameters are always strings. So we convert the 
route parameter value to a number with the JavaScript (+) operator.

The Router manages the observables it provides and localizes the subscriptions. 
The subscriptions are cleaned up when the component is destroyed, protecting 
against memory leaks, so we don't need to unsubscribe from the route params 
Observable.

Open HeroService and add a getHero method that filters the heroes list from 
getHeroes by id:

// hero.service.ts
getHero(id: number): Promise<Hero> {
  return this.getHeroes()
             .then(heroes => heroes.find(hero => hero.id === id));
}

From the HeroDetailComponent's view, The user could click one of the two links 
in the AppComponent. Or click the browser's back button. We'll add a third 
option, a goBack method that navigates backward one step in the browser's 
history stack using the Location service we injected previously.

// hero-detail.component.ts
goBack(): void {
  this.location.back();
}

Going back too far could take us out of the application. That's acceptable in a 
demo. We'd guard against it in a real application, perhaps with the 
CanDeactivate guard.

Then we wire this method with an event binding to a Back button that we add to 
the bottom of the component template.

<button (click)="goBack()">Back</button>

Modifying the template to add this button spurs us to take one more incremental 
improvement and migrate the template to its own file, called 
hero-detail.component.html:

<div *ngIf="hero">
  <h2>{{hero.name}} details!</h2>
  <div>
    <label>id: </label>{{hero.id}}</div>
  <div>
    <label>name: </label>
    <input [(ngModel)]="hero.name" placeholder="name" />
  </div>
  <button (click)="goBack()">Back</button>
</div>

We update the component metadata with a moduleId and a templateUrl pointing to 
the template file that we just created.

// hero-detail.component.ts:
@Component({
  moduleId: module.id,
  selector: 'my-hero-detail',
  templateUrl: 'hero-detail.component.html',
})

When a user selects a hero in the dashboard, the app should navigate to the 
HeroDetailComponent to view and edit the selected hero.  Although the dashboard 
heroes are presented as button-like blocks, they should behave like anchor tags. 
When hovering over a hero block, the target URL should display in the browser 
status bar and the user should be able to copy the link or open the hero detail 
view in a new tab.  To achieve this effect, reopen the dashboard.component.html 
and replace the repeated <div *ngFor...> tags with <a> tags. The opening <a> 
tag looks like this:

// dashboard.component.html
<a *ngFor="let hero of heroes"  [routerLink]="['/detail', hero.id]"  
    class="col-1-4">

Notice the [routerLink] binding.  Top level navigation in the AppComponent 
template has router links set to fixed paths of the destination routes, 
"/dashboard" and "/heroes".  This time, we're binding to an expression 
containing a link parameters array. The array has two elements, the path of the 
destination route and a route parameter set to the value of the current hero's 
id.

The two array items align with the path and :id token in the parameterized hero 
detail route definition we added to app.module.ts earlier.

// Refactor routes to a Routing Module:

So far, we have almost 20 lines of AppModule devoted to configuring routes.  
Most applications have many more routes and they add guard services to protect 
against unwanted or unauthorized navigations. Routing considerations could 
quickly dominate this module and obscure its primary purpose which is to 
establish key facts about the entire app for the Angular compiler.

We should refactor the routing configuration into its own class.   The current 
RouterModule.forRoot() produces an Angular ModuleWithProviders which suggests 
that a class dedicated to routing should be some kind of module. It should be a 
Routing Module.

By convention the name of a Routing Module contains the word "Routing" and 
aligns with the name of the module that declares the components navigated to.

Create an app-routing.module.ts file as a sibling to app.module.ts. Give it the 
following contents extracted from the AppModule class:

import { NgModule }             from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent }   from './dashboard.component';
import { HeroesComponent }      from './heroes.component';
import { HeroDetailComponent }  from './hero-detail.component';
const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard',  component: DashboardComponent },
  { path: 'detail/:id', component: HeroDetailComponent },
  { path: 'heroes',     component: HeroesComponent }
];
@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

Typical of Routing Modules:

1. Pulls the routes into a variable. You might export it in future and it 
   clarifies the Routing Module pattern.

2. Adds RouterModule.forRoot(routes) to imports.

3. Adds RouterModule to exports so that the components in the companion module 
   have access to Router declarables such as RouterLink and RouterOutlet.

4. No declarations! Declarations are the responsibility of the companion module.

5. Adds module providers for guard services if you have them; there are none in 
   this example.

Now delete the routing configuration from AppModule and import the 
AppRoutingModule (both with an ES import statement and by adding it to the 
NgModule.imports list).

Earlier we added the ability to select a hero from the dashboard. We'll do 
something similar in the HeroesComponent.  The HeroesComponent template exhibits 
a "master/detail" style with the list of heroes at the top and details of the 
selected hero below.

// heroes.components.ts (current)
template: `
  <h1>{{title}}</h1>
  <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>
  <my-hero-detail [hero]="selectedHero"></my-hero-detail>
`,

Our goal is to move the detail to its own view and navigate to it when the user 
decides to edit a selected hero.  Delete the <h1> at the top (we forgot about it 
during the AppComponent-to-HeroesComponent conversion).  Delete the last line of 
the template with the <my-hero-detail> tags.  We'll no longer show the full 
HeroDetailComponent here. We're going to display the hero detail on its own 
page and route to it as we did in the dashboard.

We'll throw in a small twist for variety. We are keeping the "master/detail" 
style but shrinking the detail to a "mini", read-only version. When the user 
selects a hero from the list, we don't go to the detail page. We show a 
mini-detail on this page instead and make the user click a button to navigate 
to the full detail page.

Add the mini-detail.  Add the following HTML fragment at the bottom of the 
template where the <my-hero-detail> used to be:

<div *ngIf="selectedHero">
  <h2>
    {{selectedHero.name | uppercase}} is my hero
  </h2>
  <button (click)="gotoDetail()">View Details</button>
</div>

Notice that the hero's name is displayed in CAPITAL LETTERS. That's the effect 
of the uppercase pipe that we slipped into the interpolation binding. Look for 
it right after the pipe operator ( | ).

{{selectedHero.name | uppercase}} is my hero

Pipes are a good way to format strings, currency amounts, dates and other 
display data. Angular ships with several pipes and we can write our own.

The styleUrls property is an array of style file names (with paths). We could 
list multiple style files from different locations if we needed them.

The HeroesComponent navigates to the HeroesDetailComponent in response to a 
button click. The button's click event is bound to a gotoDetail method that 
navigates imperatively by telling the router where to go.  This approach requires 
some changes to the component class:

1. Import the router from the Angular router library
2. Inject the router in the constructor (along with the HeroService)
3. Implement gotoDetail by calling the router.navigate method

gotoDetail(): void {
  this.router.navigate(['/detail', this.selectedHero.id]);
}

Note that we're passing a two-element link parameters array — a path and the 
route parameter — to the router.navigate method just as we did in the 
[routerLink] binding back in the DashboardComponent. Here's the fully revised 
HeroesComponent class:

// heroes.component.ts
export class HeroesComponent implements OnInit {
  heroes: Hero[];
  selectedHero: Hero;

  constructor(
    private router: Router,
    private heroService: HeroService) { }

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

  ngOnInit(): void {
    this.getHeroes();
  }

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

  gotoDetail(): void {
    this.router.navigate(['/detail', this.selectedHero.id]);
  }
}

The Angular Router provides a routerLinkActive directive we can use to add a 
class to the HTML navigation element whose route matches the active route. All 
we have to do is define the style for it.

// app.component.ts:
template: `
  <h1>{{title}}</h1>
  <nav>
    <a routerLink="/dashboard" routerLinkActive="active">Dashboard</a>
    <a routerLink="/heroes" routerLinkActive="active">Heroes</a>
  </nav>
  <router-outlet></router-outlet>
`,

When we add styles to a component, we're keeping everything a component needs — 
HTML, the CSS, the code — together in one convenient place. It's pretty easy to 
package it all up and re-use the component somewhere else.

We can also create styles at the application level outside of any component.

For styles that are common across the application, we can add it to the main
style.css file that we added to the index.html earlier on.

To do AJAX or use various http services, we need to register them all by adding
HttpModule to the imports list of the AppModule where we bootstrap the
application and its root AppComponent:

import { HttpModule }    from '@angular/http';

imports: [
  BrowserModule,
  FormsModule,
  HttpModule,
  AppRoutingModule
],

We recommend registering application-wide services in the root AppModule 
providers. 

We're going to trick the HTTP client into fetching and saving data from a mock 
service, the in-memory web API. Here is a version of app/app.module.ts that 
performs this trick:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';
import { HttpModule }    from '@angular/http';

import { AppRoutingModule } from './app-routing.module';

// Imports for loading & configuring the in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService }  from './in-memory-data.service';

import { AppComponent }         from './app.component';
import { DashboardComponent }   from './dashboard.component';
import { HeroesComponent }      from './heroes.component';
import { HeroDetailComponent }  from './hero-detail.component';
import { HeroService }          from './hero.service';

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    InMemoryWebApiModule.forRoot(InMemoryDataService),
    AppRoutingModule
  ],
  declarations: [
    AppComponent,
    DashboardComponent,
    HeroDetailComponent,
    HeroesComponent,
  ],
  providers: [ HeroService ],
  bootstrap: [ AppComponent ]
})
export class AppModule { }

Notice that we import the InMemoryWebApiModule and adding it to the module 
imports. The InMemoryWebApiModule replaces the default Http client backend — 
the supporting service that talks to the remote server — with an in-memory web 
API alternative service.

InMemoryWebApiModule.forRoot(InMemoryDataService)

The forRoot configuration method takes an InMemoryDataService class that primes 
the in-memory database as follows:

//in-memory-data.service.ts
import { InMemoryDbService } from 'angular-in-memory-web-api';
export class InMemoryDataService implements InMemoryDbService {
  createDb() {
    let heroes = [
      {id: 11, name: 'Mr. Nice'},
      {id: 12, name: 'Narco'},
      {id: 13, name: 'Bombasto'},
      {id: 14, name: 'Celeritas'},
      {id: 15, name: 'Magneta'},
      {id: 16, name: 'RubberMan'},
      {id: 17, name: 'Dynama'},
      {id: 18, name: 'Dr IQ'},
      {id: 19, name: 'Magma'},
      {id: 20, name: 'Tornado'}
    ];
    return {heroes};
  }
}

This file replaces the mock-heroes.ts.

The in-memory web API is only useful in the early stages of development and for 
demonstrations.  Look at our current HeroService implementation:

getHeroes(): Promise<Hero[]> {
  return Promise.resolve(HEROES);
}

We returned a Promise resolved with mock heroes. It may have seemed like 
overkill at the time, but we were anticipating the day when we fetched heroes 
with an HTTP client and we knew that would have to be an asynchronous operation.
Let's convert getHeroes() to use HTTP:

//hero.service.ts:
private heroesUrl = 'app/heroes';  // URL to web api

constructor(private http: Http) { }

getHeroes(): Promise<Hero[]> {
return this.http.get(this.heroesUrl)
           .toPromise()
           .then(response => response.json().data as Hero[])
           .catch(this.handleError);
}

Our updated import statements are now:

//hero.service.ts
import { Injectable }    from '@angular/core';
import { Headers, Http } from '@angular/http';

import 'rxjs/add/operator/toPromise';

import { Hero } from './hero';

The Angular http.get returns an RxJS Observable. Observables are a powerful way 
to manage asynchronous data flows. For now we get back on familiar ground by 
immediately converting that Observable to a Promise using the toPromise operator.

Unfortunately, the Angular Observable doesn't have a toPromise operator ... not 
out of the box. The Angular Observable is a bare-bones implementation.

There are scores of operators like toPromise that extend Observable with useful 
capabilities. If we want those capabilities, we have to add the operators 
ourselves. That's as easy as importing them from the RxJS library like this:

import 'rxjs/add/operator/toPromise';

In the promise's then callback we call the json method of the HTTP Response to 
extract the data within the response:

.then(response => response.json().data as Hero[])

That response JSON has a single data property. The data property holds the array 
of heroes that the caller really wants. So we grab that array and return it as 
the resolved Promise value.

This particular in-memory web API example happens to return an object with a 
data property. Your API might return something else. Adjust the code to match 
your web API.

The caller is unaware of these machinations. It receives a Promise of heroes 
just as it did before. It has no idea that we fetched the heroes from the (mock) 
server. It knows nothing of the twists and turns required to convert the HTTP 
response into heroes. Such is the beauty and purpose of delegating data access 
to a service.

At the end of getHeroes() we catch server failures and pass them to an error 
handler:

.catch(this.handleError);

We must anticipate HTTP failures as they happen frequently for reasons beyond 
our control.

private handleError(error: any): Promise<any> {
  console.error('An error occurred', error); // for demo purposes only
  return Promise.reject(error.message || error);
}

To persist the data, start by adding, to the end of the hero detail template, a 
save button with a click event binding that invokes a new component method named 
save:

//hero-detail.component.html
<button (click)="save()">Save</button>

The save method persists hero name changes using the hero service update method 
and then navigates back to the previous view:

//hero-detail.component.ts
save(): void {
  this.heroService.update(this.hero)
    .then(() => this.goBack());
}

The overall structure of the update method is similar to that of getHeroes, 
although we'll use an HTTP put to persist changes server-side:

//hero.service.ts
private headers = new Headers({'Content-Type': 'application/json'});

update(hero: Hero): Promise<Hero> {
  const url = `${this.heroesUrl}/${hero.id}`;
  return this.http
    .put(url, JSON.stringify(hero), {headers: this.headers})
    .toPromise()
    .then(() => hero)
    .catch(this.handleError);
}

We identify which hero the server should update by encoding the hero id in the 
URL. The put body is the JSON string encoding of the hero, obtained by calling 
JSON.stringify. We identify the body content type (application/json) in the 
request header.

To add a new hero we need to know the hero's name. Let's use an input element 
for that, paired with an add button.  Insert the following into the heroes 
component HTML, first thing after the heading:

<div>
  <label>Hero name:</label> <input #heroName />
  <button (click)="add(heroName.value); heroName.value=''">
    Add
  </button>
</div>

In response to a click event, we call the component's click handler and then 
clear the input field so that it will be ready to use for another name.

//heroes.component.ts
add(name: string): void {
  name = name.trim();
  if (!name) { return; }
  this.heroService.create(name)
    .then(hero => {
      this.heroes.push(hero);
      this.selectedHero = null;
    });
}

When the given name is non-blank, the handler delegates creation of the named 
hero to the hero service, and then adds the new hero to our array.  Finally, we 
implement the create method in the HeroService class.

//hero.service.ts
create(name: string): Promise<Hero> {
  return this.http
    .post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers})
    .toPromise()
    .then(res => res.json().data)
    .catch(this.handleError);
}

To delete heroes, let's add a delete button to each hero in the heroes view.  
Add this button element to the heroes component HTML, right after the hero name 
in the repeated <li> tag:

<button class="delete"
  (click)="delete(hero); $event.stopPropagation()">x</button>

The <li> element should now look like this:

<li *ngFor="let hero of heroes" (click)="onSelect(hero)"
  [class.selected]="hero === selectedHero">
<span class="badge">{{hero.id}}</span>
<span>{{hero.name}}</span>
<button class="delete"
  (click)="delete(hero); $event.stopPropagation()">x</button>
</li>

In addition to calling the component's delete method, the delete button click 
handling code stops the propagation of the click event — we don't want the <li> 
click handler to be triggered because that would select the hero that we just
deleted.

The logic of the delete handler is a bit trickier:

delete(hero: Hero): void {
  this.heroService
      .delete(hero.id)
      .then(() => {
        this.heroes = this.heroes.filter(h => h !== hero);
        if (this.selectedHero === hero) { this.selectedHero = null; }
      });
}

We delegate hero deletion to the hero service, but the component is still 
responsible for updating the display: it removes the deleted hero from the array 
and resets the selected hero if necessary.

The hero service's delete method uses the delete HTTP method to remove the hero 
from the server:

delete(id: number): Promise<void> {
  const url = `${this.heroesUrl}/${id}`;
  return this.http.delete(url, {headers: this.headers})
    .toPromise()
    .then(() => null)
    .catch(this.handleError);
}

Each Http service method returns an Observable of HTTP Response objects.  Our 
HeroService converts that Observable into a Promise and returns the promise to 
the caller. In this section we learn to return the Observable directly and 
discuss when and why that might be a good thing to do.

An observable is a stream of events that we can process with array-like 
operators.  Angular core has basic support for observables. We developers 
augment that support with operators and extensions from the RxJS Observables 
library.

Recall that our HeroService quickly chained the toPromise operator to the 
Observable result of http.get. That operator converted the Observable into a 
Promise and we passed that promise back to the caller.

Converting to a promise is often a good choice. We typically ask http.get to 
fetch a single chunk of data. When we receive the data, we're done. A single 
result in the form of a promise is easy for the calling component to consume 
and it helps that promises are widely understood by JavaScript programmers.

But requests aren't always "one and done". We may start one request, then 
cancel it, and make a different request before the server has responded to the 
first request. Such a request-cancel-new-request sequence is difficult to 
implement with Promises. It's easy with Observables.

We're going to add a hero search feature to the Tour of Heroes. As the user 
types a name into a search box, we'll make repeated HTTP requests for heroes 
filtered by that name.

We start by creating HeroSearchService that sends search queries to our 
server's web api.

//hero-search.service.ts
import { Injectable }     from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs';
import { Hero }           from './hero';
@Injectable()
export class HeroSearchService {
  constructor(private http: Http) {}
  search(term: string): Observable<Hero[]> {
    return this.http
               .get(`app/heroes/?name=${term}`)
               .map((r: Response) => r.json().data as Hero[]);
  }
}

The http.get() call in HeroSearchService is similar to the one in the 
HeroService, although the URL now has a query string. Another notable 
difference: we no longer call toPromise, we simply return the observable 
instead.

Let's create a new HeroSearchComponent that calls this new HeroSearchService.  
The component template is simple — just a text box and a list of matching search 
results.

//hero-search.component.html
<div id="search-component">
  <h4>Hero Search</h4>
  <input #searchBox id="search-box" (keyup)="search(searchBox.value)" />
  <div>
    <div *ngFor="let hero of heroes | async"
         (click)="gotoDetail(hero)" class="search-result" >
      {{hero.name}}
    </div>
  </div>
</div>

As the user types in the search box, a keyup event binding calls the component's 
search method with the new search box value.

The *ngFor repeats hero objects from the component's heroes property. No 
surprise there.  But the heroes property is now an Observable of hero arrays, 
rather than just a hero array. The *ngFor can't do anything with an Observable 
until we flow it through the async pipe (AsyncPipe). The async pipe subscribes 
to the Observable and produces the array of heroes to *ngFor.

The HeroSearchComponent class and metadata:

//hero-search.component.ts
import { Component, OnInit } from '@angular/core';
import { Router }            from '@angular/router';
import { Observable }        from 'rxjs/Observable';
import { Subject }           from 'rxjs/Subject';
import { HeroSearchService } from './hero-search.service';
import { Hero } from './hero';
@Component({
  moduleId: module.id,
  selector: 'hero-search',
  templateUrl: 'hero-search.component.html',
  styleUrls: [ 'hero-search.component.css' ],
  providers: [HeroSearchService]
})
export class HeroSearchComponent implements OnInit {
  heroes: Observable<Hero[]>;
  private searchTerms = new Subject<string>();
  constructor(
    private heroSearchService: HeroSearchService,
    private router: Router) {}
  // Push a search term into the observable stream.
  search(term: string): void {
    this.searchTerms.next(term);
  }
  ngOnInit(): void {
    this.heroes = this.searchTerms
      .debounceTime(300)        // wait for 300ms pause in events
      .distinctUntilChanged()   // ignore if next search term is same as previous
      .switchMap(term => term   // switch to new observable each time
        // return the http search observable
        ? this.heroSearchService.search(term)
        // or the observable of empty heroes if no search term
        : Observable.of<Hero[]>([]))
      .catch(error => {
        // TODO: real error handling
        console.log(error);
        return Observable.of<Hero[]>([]);
      });
  }
  gotoDetail(hero: Hero): void {
    let link = ['/detail', hero.id];
    this.router.navigate(link);
  }
}

Let's focus on the searchTerms:

private searchTerms = new Subject<string>();

// Push a search term into the observable stream.
search(term: string): void {
  this.searchTerms.next(term);
}

A Subject is a producer of an observable event stream; searchTerms produces an 
Observable of strings, the filter criteria for the name search.  Each call to 
search puts a new string into this subject's observable stream by calling next.

A Subject is also an Observable. We're going to turn the stream of search terms 
into a stream of Hero arrays and assign the result to the heroes property.

heroes: Observable<Hero[]>;

ngOnInit(): void {
  this.heroes = this.searchTerms
    .debounceTime(300)        // wait for 300ms pause in events
    .distinctUntilChanged()   // ignore if next search term is same as previous
    .switchMap(term => term   // switch to new observable each time
      // return the http search observable
      ? this.heroSearchService.search(term)
      // or the observable of empty heroes if no search term
      : Observable.of<Hero[]>([]))
    .catch(error => {
      // TODO: real error handling
      console.log(error);
      return Observable.of<Hero[]>([]);
    });
}

If we passed every user keystroke directly to the HeroSearchService, we'd 
unleash a storm of HTTP requests. Bad idea. We don't want to tax our server 
resources and burn through our cellular network data plan.

Fortunately, we can chain Observable operators to the string Observable that 
reduce the request flow. We'll make fewer calls to the HeroSearchService and 
still get timely results. Here's how:

1. debounceTime(300) waits until the flow of new string events pauses for 300 
   milliseconds before passing along the latest string. We'll never make 
   requests more frequently than 300ms.

2. distinctUntilChanged ensures that we only send a request if the filter text 
   changed. There's no point in repeating a request for the same search term.

3. switchMap calls our search service for each search term that makes it through 
   the debounce and distinctUntilChanged gauntlet. It cancels and discards 
   previous search observables, returning only the latest search service 
   observable.

4. catch intercepts a failed observable. Our simple example prints the error to 
   the console; a real life application should do better. Then we return an 
   observable containing an empty array to clear the search result.

The switchMap operator (formerly known as "flatMapLatest") is very clever.  
Every qualifying key event can trigger an http method call. Even with a 300ms 
pause between requests, we could have multiple HTTP requests in flight and they 
may not return in the order sent.

switchMap preserves the original request order while returning only the 
observable from the most recent http method call. Results from prior calls are 
canceled and discarded.

We also short-circuit the http method call and return an observable containing 
an empty array if the search text is empty.  Note that canceling the 
HeroSearchService observable won't actually abort a pending HTTP request until 
the service supports that feature, a topic for another day. We are content for 
now to discard unwanted results.

The RxJS operators are not available in Angular's base Observable implementation. 
We have to extend Observable by importing them.  We could extend Observable with 
just the operators we need here by including the pertinent import statements at 
the top of this file.  Many authorities say we should do just that.  We take a 
different approach in this example. We combine all of the RxJS Observable 
extensions that our entire app requires into a single RxJS imports file.

//rxjs-extensions.ts

// Observable class extensions
import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';

// Observable operators
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';

We load them all at once by importing rxjs-extensions at the top of AppModule.

//app.module.ts 
import './rxjs-extensions';

To add  the search component to the dashboard, we add the hero search HTML 
element to the bottom of the DashboardComponent template.

//dashboard.component.html
<h3>Top Heroes</h3>
<div class="grid grid-pad">
  <a *ngFor="let hero of heroes"  [routerLink]="['/detail', hero.id]"  class="col-1-4">
    <div class="module hero">
      <h4>{{hero.name}}</h4>
    </div>
  </a>
</div>
<hero-search></hero-search>

Finally, we import HeroSearchComponent from hero-search.component.ts and add it 
to the declarations array:

//app.module.ts
declarations: [
  AppComponent,
  DashboardComponent,
  HeroDetailComponent,
  HeroesComponent,
  HeroSearchComponent
],

ng build // build our project
    // The build artifacts will be stored in the dist/ directory.

Build for a specific target or environment:

# these are equivalent
ng build --target=production --environment=prod
ng build --prod --env=prod
ng build --prod

# and so are these
ng build --target=development --environment=dev
ng build --dev --e=dev
ng build --dev
ng build

ng build can specify both a build target (—target=production or 
—target=development) and an environment file to be used with that build 
(--environment=dev or --environment=prod). By default, the development build 
target and environment are used.

The mapping used to determine which environment file is used can be found in 
angular-cli.json:

"environments": {
  "source": "environments/environment.ts",
  "dev": "environments/environment.ts",
  "prod": "environments/environment.prod.ts"
}

These options also apply to the serve command. If you do not pass a value for 
environment, it will default to dev for development and prod for production.

You can also add your own env files other than dev and prod by doing the 
following:

1. create a src/environments/environment.NAME.ts

2. add { "NAME": 'src/environments/environment.NAME.ts' } 
   to the the apps[0].environments object in angular-cli.json

3. use them via the --env=NAME flag on the build/serve commands.

When building you can modify base tag (<base href="/">) in your index.html 
with --base-href your-url option:

ng build --base-href /myUrl/
ng build --bh /myUrl/

Tests will execute after a build is executed via Karma, and it will 
automatically watch your files for changes. You can run tests a single time 
via --watch=false.

Before running the tests make sure you are serving the app via ng serve. 
End-to-end tests are run via Protractor

Using the proxying support in webpack's dev server we can highjack certain urls 
and send them to a backend server. We do this by passing a file to 
--proxy-config. Say we have a server running on http://localhost:3000/api and 
we want all calls th http://localhost:4200/api to go to that server. We create 
a file next to projects package.json called proxy.conf.json with the content:

{
  "/api": {
    "target": "http://localhost:3000",
    "secure": false
  }
}

We can read more about what options are available at
https://webpack.github.io/docs/webpack-dev-server.html#proxy. And then we edit 
the package.json file's start script to be:

"start": "ng serve --proxy-config proxy.conf.json",

now run it with npm start.

Deploy our application via GitHub Pages:

ng github-pages:deploy --message "Optional commit message"

This will do the following:

1. creates GitHub repo for the current project if one doesn't exist
2. rebuilds the app in production mode at the current HEAD
3. creates a local gh-pages branch if one doesn't exist
4. moves your app to the gh-pages branch and creates a commit
5. edit the base tag in index.html to support github pages
6. pushes the gh-pages branch to github
7. returns back to the original HEAD

Creating the repo requires a token from github, and the remaining functionality 
relies on ssh authentication for all git operations that communicate with 
github.com. To simplify the authentication, be sure to setup your ssh keys. 
If you are deploying a user or organization page, you can instead use the 
following command:

ng github-pages:deploy --user-page --message "Optional commit message"

This command pushes the app to the master branch on the github repo instead of 
pushing to gh-pages, since user and organization pages require this.

To lint and format our code:

ng lint

This will use the lint npm script that in generated projects uses tslint. You 
can modify the these scripts in package.json to run whatever tool you prefer.

Angular-CLI supports all major CSS preprocessors.  To use these prepocessors 
simply add the file to your component's styleUrls:

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

When generating a new project you can also define which extension you want 
for style files:

ng new applicationName --style=sass

Or set the default style on an existing project:

ng set defaults.styleExt scss
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License