docs(server-communication): fix http after testing chapter discoveries
This commit is contained in:
parent
dd7b5176a8
commit
353abff084
|
@ -1,15 +1,21 @@
|
|||
//#docregion
|
||||
import {bootstrap} from 'angular2/platform/browser';
|
||||
// #docplaster
|
||||
// #docregion
|
||||
import { bootstrap } from 'angular2/platform/browser';
|
||||
// #docregion http-providers
|
||||
import { HTTP_PROVIDERS } from 'angular2/http';
|
||||
// #enddocregion http-providers
|
||||
|
||||
// #docregion import-rxjs
|
||||
// Add all operators to Observable
|
||||
import 'rxjs/Rx';
|
||||
// #enddocregion import-rxjs
|
||||
|
||||
import {WikiComponent} from './wiki/wiki.component';
|
||||
import {WikiSmartComponent} from './wiki/wiki-smart.component';
|
||||
import {TohComponent} from './toh/toh.component';
|
||||
import { WikiComponent } from './wiki/wiki.component';
|
||||
import { WikiSmartComponent } from './wiki/wiki-smart.component';
|
||||
import { TohComponent } from './toh/toh.component';
|
||||
|
||||
bootstrap(WikiComponent);
|
||||
bootstrap(WikiSmartComponent);
|
||||
bootstrap(TohComponent);
|
||||
// #docregion http-providers
|
||||
bootstrap(TohComponent, [HTTP_PROVIDERS]);
|
||||
// #enddocregion http-providers
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// ToH Promise Version
|
||||
// #docregion
|
||||
import {Component, OnInit} from 'angular2/core';
|
||||
import {Hero} from './hero';
|
||||
|
@ -5,22 +6,7 @@ import {HeroService} from './hero.service.1';
|
|||
|
||||
@Component({
|
||||
selector: 'hero-list',
|
||||
// #docregion template
|
||||
template: `
|
||||
<h3>Heroes:</h3>
|
||||
<ul>
|
||||
<li *ngFor="#hero of heroes">
|
||||
{{ hero.name }}
|
||||
</li>
|
||||
</ul>
|
||||
New Hero:
|
||||
<input #newHero />
|
||||
<button (click)="addHero(newHero.value); newHero.value=''">
|
||||
Add Hero
|
||||
</button>
|
||||
<div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
|
||||
`,
|
||||
// #enddocregion template
|
||||
templateUrl: 'app/toh/hero-list.component.html',
|
||||
styles: ['.error {color:red;}']
|
||||
})
|
||||
// #docregion component
|
||||
|
@ -29,7 +15,7 @@ export class HeroListComponent implements OnInit {
|
|||
constructor (private _heroService: HeroService) {}
|
||||
|
||||
errorMessage: string;
|
||||
heroes:Hero[];
|
||||
heroes: Hero[];
|
||||
|
||||
ngOnInit() { this.getHeroes(); }
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- #docregion -->
|
||||
<h3>Heroes:</h3>
|
||||
<ul>
|
||||
<li *ngFor="#hero of heroes">
|
||||
{{ hero.name }}
|
||||
</li>
|
||||
</ul>
|
||||
New Hero:
|
||||
<input #newHero />
|
||||
<button (click)="addHero(newHero.value); newHero.value=''">
|
||||
Add Hero
|
||||
</button>
|
||||
<div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
|
|
@ -5,20 +5,7 @@ import {HeroService} from './hero.service';
|
|||
|
||||
@Component({
|
||||
selector: 'hero-list',
|
||||
template: `
|
||||
<h3>Heroes:</h3>
|
||||
<ul>
|
||||
<li *ngFor="#hero of heroes">
|
||||
{{ hero.name }}
|
||||
</li>
|
||||
</ul>
|
||||
New Hero:
|
||||
<input #newHero />
|
||||
<button (click)="addHero(newHero.value); newHero.value=''">
|
||||
Add Hero
|
||||
</button>
|
||||
<div class="error" *ngIf="errorMessage">{{errorMessage}}</div>
|
||||
`,
|
||||
templateUrl: 'app/toh/hero-list.component.html',
|
||||
styles: ['.error {color:red;}']
|
||||
})
|
||||
// #docregion component
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* Promise version */
|
||||
// ToH Promise Version
|
||||
// #docplaster
|
||||
|
||||
// #docregion
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {Http} from 'angular2/http';
|
||||
import {Http, Response} from 'angular2/http';
|
||||
import {Headers, RequestOptions} from 'angular2/http';
|
||||
import {Hero} from './hero';
|
||||
|
||||
|
@ -15,27 +15,36 @@ export class HeroService {
|
|||
private _heroesUrl = 'app/heroes.json';
|
||||
|
||||
// #docregion methods
|
||||
getHeroes () {
|
||||
getHeroes (): Promise<Hero[]> {
|
||||
return this.http.get(this._heroesUrl)
|
||||
.toPromise()
|
||||
.then(res => <Hero[]> res.json().data, this.handleError)
|
||||
.then(data => { console.log(data); return data; }); // eyeball results in the console
|
||||
.then(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
addHero (name: string) : Promise<Hero> {
|
||||
addHero (name: string): Promise<Hero> {
|
||||
let body = JSON.stringify({ name });
|
||||
let headers = new Headers({ 'Content-Type': 'application/json' });
|
||||
let options = new RequestOptions({ headers: headers });
|
||||
|
||||
return this.http.post(this._heroesUrl, body, options)
|
||||
.toPromise()
|
||||
.then(res => <Hero> res.json().data)
|
||||
.then(this.extractData)
|
||||
.catch(this.handleError);
|
||||
}
|
||||
|
||||
private extractData(res: Response) {
|
||||
if (res.status < 200 || res.status >= 300) {
|
||||
throw new Error('Bad response status: ' + res.status);
|
||||
}
|
||||
let body = res.json();
|
||||
return body.data || { };
|
||||
}
|
||||
|
||||
private handleError (error: any) {
|
||||
// in a real world app, we may send the error to some remote logging infrastructure
|
||||
console.error(error); // log to console instead
|
||||
// In a real world app, we might send the error to remote logging infrastructure
|
||||
let errMsg = error.message || 'Server error';
|
||||
console.error(errMsg); // log to console instead
|
||||
return Promise.reject(errMsg);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// #docregion
|
||||
// #docregion v1
|
||||
import {Injectable} from 'angular2/core';
|
||||
import {Http} from 'angular2/http';
|
||||
import {Http, Response} from 'angular2/http';
|
||||
// #enddocregion v1
|
||||
// #docregion import-request-options
|
||||
import {Headers, RequestOptions} from 'angular2/http';
|
||||
|
@ -31,18 +31,13 @@ export class HeroService {
|
|||
// #enddocregion endpoint
|
||||
|
||||
// #docregion methods
|
||||
// #docregion error-handling
|
||||
// #docregion error-handling, http-get
|
||||
getHeroes (): Observable<Hero[]> {
|
||||
// #docregion http-get, http-get-v1
|
||||
return this.http.get(this._heroesUrl)
|
||||
.map(this.extractData)
|
||||
// #enddocregion v1, http-get-v1, error-handling
|
||||
.do(data => console.log(data)) // eyeball results in the console
|
||||
// #docregion v1, http-get-v1, error-handling
|
||||
.catch(this.handleError);
|
||||
// #enddocregion http-get, http-get-v1
|
||||
}
|
||||
// #enddocregion error-handling
|
||||
// #enddocregion error-handling, http-get
|
||||
// #enddocregion v1
|
||||
|
||||
// #docregion addhero
|
||||
|
@ -62,6 +57,7 @@ export class HeroService {
|
|||
|
||||
// #docregion v1
|
||||
|
||||
// #docregion extract-data
|
||||
private extractData(res: Response) {
|
||||
if (res.status < 200 || res.status >= 300) {
|
||||
throw new Error('Bad response status: ' + res.status);
|
||||
|
@ -69,12 +65,13 @@ export class HeroService {
|
|||
let body = res.json();
|
||||
return body.data || { };
|
||||
}
|
||||
// #enddocregion extract-data
|
||||
|
||||
// #docregion error-handling
|
||||
private handleError (error: any) {
|
||||
// in a real world app, we may send the error to some remote logging infrastructure
|
||||
console.error(error); // log to console instead
|
||||
// In a real world app, we might send the error to remote logging infrastructure
|
||||
let errMsg = error.message || 'Server error';
|
||||
console.error(errMsg); // log to console instead
|
||||
return Observable.throw(errMsg);
|
||||
}
|
||||
// #enddocregion error-handling
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// ToH Promise Version
|
||||
console.log ('Promise version');
|
||||
|
||||
import { Component } from 'angular2/core';
|
||||
import { HTTP_PROVIDERS } from 'angular2/http';
|
||||
|
||||
import { HeroListComponent } from './hero-list.component.1';
|
||||
import { HeroService } from './hero.service.1';
|
||||
|
||||
import { provide } from 'angular2/core';
|
||||
import { XHRBackend } from 'angular2/http';
|
||||
|
||||
import { InMemoryBackendService,
|
||||
SEED_DATA } from 'a2-in-memory-web-api/core';
|
||||
import { HeroData } from '../hero-data';
|
||||
|
||||
@Component({
|
||||
selector: 'my-toh',
|
||||
template: `
|
||||
<h1>Tour of Heroes</h1>
|
||||
<hero-list></hero-list>
|
||||
`,
|
||||
directives:[HeroListComponent],
|
||||
providers: [
|
||||
HTTP_PROVIDERS,
|
||||
HeroService,
|
||||
// in-memory web api providers
|
||||
provide(XHRBackend, { useClass: InMemoryBackendService }), // in-mem server
|
||||
provide(SEED_DATA, { useClass: HeroData }) // in-mem server data
|
||||
]
|
||||
})
|
||||
export class TohComponent { }
|
|
@ -0,0 +1,44 @@
|
|||
// #docplaster
|
||||
|
||||
// #docregion
|
||||
import { Component } from 'angular2/core';
|
||||
import { HTTP_PROVIDERS } from 'angular2/http';
|
||||
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroService } from './hero.service';
|
||||
// #enddocregion
|
||||
|
||||
// #docregion in-mem-web-api-imports
|
||||
import { provide } from 'angular2/core';
|
||||
import { XHRBackend } from 'angular2/http';
|
||||
|
||||
// in-memory web api imports
|
||||
import { InMemoryBackendService,
|
||||
SEED_DATA } from 'a2-in-memory-web-api/core';
|
||||
import { HeroData } from '../hero-data';
|
||||
// #enddocregion in-mem-web-api-imports
|
||||
// #docregion
|
||||
|
||||
@Component({
|
||||
selector: 'my-toh',
|
||||
// #docregion template
|
||||
template: `
|
||||
<h1>Tour of Heroes</h1>
|
||||
<hero-list></hero-list>
|
||||
`,
|
||||
// #enddocregion template
|
||||
directives: [HeroListComponent],
|
||||
providers: [
|
||||
HTTP_PROVIDERS,
|
||||
HeroService,
|
||||
// #enddocregion
|
||||
// #docregion in-mem-web-api-providers
|
||||
// in-memory web api providers
|
||||
provide(XHRBackend, { useClass: InMemoryBackendService }), // in-mem server
|
||||
provide(SEED_DATA, { useClass: HeroData }) // in-mem server data
|
||||
// #enddocregion in-mem-web-api-providers
|
||||
// #docregion
|
||||
]
|
||||
})
|
||||
export class TohComponent { }
|
||||
// #enddocregion
|
|
@ -1,24 +1,23 @@
|
|||
// #docplaster
|
||||
|
||||
// #docregion
|
||||
import {Component} from 'angular2/core';
|
||||
import {HTTP_PROVIDERS} from 'angular2/http';
|
||||
import { Component } from 'angular2/core';
|
||||
import { HTTP_PROVIDERS } from 'angular2/http';
|
||||
|
||||
import {Hero} from './hero';
|
||||
import {HeroListComponent} from './hero-list.component';
|
||||
import {HeroService} from './hero.service';
|
||||
//#enddocregion
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroService } from './hero.service';
|
||||
// #enddocregion
|
||||
|
||||
//#docregion in-mem-web-api-imports
|
||||
import {provide} from 'angular2/core';
|
||||
import {XHRBackend} from 'angular2/http';
|
||||
// #docregion in-mem-web-api-imports
|
||||
import { provide } from 'angular2/core';
|
||||
import { XHRBackend } from 'angular2/http';
|
||||
|
||||
// in-memory web api imports
|
||||
import {InMemoryBackendService,
|
||||
SEED_DATA} from 'a2-in-memory-web-api/core';
|
||||
import {HeroData} from '../hero-data';
|
||||
import { InMemoryBackendService,
|
||||
SEED_DATA } from 'a2-in-memory-web-api/core';
|
||||
import { HeroData } from '../hero-data';
|
||||
// #enddocregion in-mem-web-api-imports
|
||||
//#docregion
|
||||
// #docregion
|
||||
|
||||
@Component({
|
||||
selector: 'my-toh',
|
||||
|
@ -28,17 +27,17 @@ import {HeroData} from '../hero-data';
|
|||
<hero-list></hero-list>
|
||||
`,
|
||||
// #enddocregion template
|
||||
directives:[HeroListComponent],
|
||||
providers: [
|
||||
directives: [HeroListComponent],
|
||||
providers: [
|
||||
HTTP_PROVIDERS,
|
||||
HeroService,
|
||||
//#enddocregion
|
||||
//#docregion in-mem-web-api-providers
|
||||
// #enddocregion
|
||||
// #docregion in-mem-web-api-providers
|
||||
// in-memory web api providers
|
||||
provide(XHRBackend, { useClass: InMemoryBackendService }), // in-mem server
|
||||
provide(SEED_DATA, { useClass: HeroData }) // in-mem server data
|
||||
//#enddocregion in-mem-web-api-providers
|
||||
//#docregion
|
||||
// #enddocregion in-mem-web-api-providers
|
||||
// #docregion
|
||||
]
|
||||
})
|
||||
export class TohComponent { }
|
||||
|
|
|
@ -36,7 +36,7 @@ export class HeroService {
|
|||
}
|
||||
|
||||
private handleError (error: any) {
|
||||
// in a real world app, we may send the error to some remote logging infrastructure
|
||||
// In a real world app, we might send the error to remote logging infrastructure
|
||||
let errMsg = error.message || 'Server error';
|
||||
console.error(errMsg); // log to console instead
|
||||
return Observable.throw(errMsg);
|
||||
|
|
|
@ -21,7 +21,6 @@ include ../_util-fns
|
|||
[Enabling RxJS Operators](#enable-rxjs-operators)<br>
|
||||
[Extract JSON data with RxJS map](#map)<br>
|
||||
[Error handling](#error-handling)<br>
|
||||
[Log results to console](#do)<br>
|
||||
[Send data to the server](#update)<br>
|
||||
[Add headers](#headers)<br>
|
||||
[Promises instead of observables](#promises)<br>
|
||||
|
@ -67,14 +66,20 @@ figure.image-display
|
|||
making them available to the child components of this "Tour of Heroes" application.
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
Alternatively, we may choose to add the `HTTP_PROVIDERS` while bootstrapping the app:
|
||||
+makeExample('server-communication/ts/app/main.ts','http-providers','app/main.ts')(format='.')
|
||||
:marked
|
||||
Learn about providers in the [Dependency Injection](dependency-injection.html) chapter.
|
||||
|
||||
:marked
|
||||
This sample only has one child, the `HeroListComponent` shown here in full:
|
||||
+makeExample('server-communication/ts/app/toh/hero-list.component.ts', null, 'app/toh/hero-list.component.ts')
|
||||
This sample only has one child, the `HeroListComponent`. Here's its template:
|
||||
+makeExample('server-communication/ts/app/toh/hero-list.component.html', null, 'app/toh/hero-list.component.html (Template)')
|
||||
:marked
|
||||
The component template displays a list of heroes with the `NgFor` repeater directive.
|
||||
|
||||
figure.image-display
|
||||
img(src='/resources/images/devguide/server-communication/hero-list.png' alt="Hero List")
|
||||
:marked
|
||||
Beneath the heroes is an input box and an *Add Hero* button where we can enter the names of new heroes
|
||||
and add them to the database.
|
||||
We use a [local template variable](template-syntax.html#local-vars), `newHero`, to access the
|
||||
|
@ -82,22 +87,26 @@ figure.image-display
|
|||
When the user clicks the button, we pass that value to the component's `addHero` method and then
|
||||
clear it to make ready for a new hero name.
|
||||
|
||||
Below the button is an optional error message.
|
||||
Below the button is a (hidden) area for an error message.
|
||||
|
||||
a(id="oninit")
|
||||
a(id="HeroListComponent")
|
||||
:marked
|
||||
### The *HeroListComponent* class
|
||||
Here's the component class:
|
||||
+makeExample('server-communication/ts/app/toh/hero-list.component.ts','component', 'app/toh/hero-list.component.ts (class)')
|
||||
:marked
|
||||
We [inject](dependency-injection.html) the `HeroService` into the constructor.
|
||||
That's the instance of the `HeroService` that we provided in the parent shell `TohComponent`.
|
||||
|
||||
Notice that the component **does not talk to the server directly!**
|
||||
The component doesn't know or care how we get the data.
|
||||
Those details it delegates to the `heroService` class (which we'll get to in a moment).
|
||||
This is a golden rule: *always delegate data access to a supporting service class*.
|
||||
|
||||
This is a golden rule: **always delegate data access to a supporting service class**.
|
||||
|
||||
Although the component should request heroes immediately,
|
||||
we do **not** call the service `get` method in the component's constructor.
|
||||
Although _at runtime_ the component requests heroes immediately after creation,
|
||||
we do **not** call the service's `get` method in the component's constructor.
|
||||
We call it inside the `ngOnInit` [lifecycle hook](lifecycle-hooks.html) instead
|
||||
and count on Angular to call `ngOnInit` when it instantiates this component.
|
||||
.l-sub-section
|
||||
|
@ -106,8 +115,9 @@ a(id="HeroListComponent")
|
|||
Components are easier to test and debug when their constructors are simple and all real work
|
||||
(especially calling a remote server) is handled in a separate method.
|
||||
:marked
|
||||
The service `get` and `addHero` methods return an `Observable` of HTTP Responses to which we `subscribe`,
|
||||
specifying the actions to take if a method succeeds or fails.
|
||||
The service `get` and `addHero` methods return an `Observable` of HTTP hero data.
|
||||
We subscribe to this `Observable`,
|
||||
specifying the actions to take when the request succeeds or fails.
|
||||
We'll get to observables and subscription shortly.
|
||||
|
||||
With our basic intuitions about the component squared away, we can turn to development of the backend data source
|
||||
|
@ -122,7 +132,7 @@ a(id="HeroListComponent")
|
|||
In this chapter, we get the heroes from the server using Angular's own HTTP Client service.
|
||||
Here's the new `HeroService`:
|
||||
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'v1', 'app/toh/hero.service.ts')(format=".")
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'v1', 'app/toh/hero.service.ts')
|
||||
:marked
|
||||
We begin by importing Angular's `Http` client service and
|
||||
[inject it](dependency-injection.html) into the `HeroService` constructor.
|
||||
|
@ -133,7 +143,7 @@ a(id="HeroListComponent")
|
|||
+makeExample('server-communication/ts/index.html', 'http', 'index.html')(format=".")
|
||||
:marked
|
||||
Look closely at how we call `http.get`
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'http-get-v1', 'app/toh/hero.service.ts (http.get)')(format=".")
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'http-get', 'app/toh/hero.service.ts (getHeroes)')(format=".")
|
||||
:marked
|
||||
We pass the resource URL to `get` and it calls the server which should return heroes.
|
||||
.l-sub-section
|
||||
|
@ -153,13 +163,6 @@ a(id="HeroListComponent")
|
|||
|
||||
In fact, the `http.get` method returns an **Observable** of HTTP Responses (`Observable<Response>`) from the RxJS library
|
||||
and `map` is one of the RxJS *operators*.
|
||||
.callout.is-important
|
||||
header HTTP GET Delayed
|
||||
:marked
|
||||
The `http.get` does **not send the request just yet!** This observable is
|
||||
[*cold*](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md#cold-vs-hot-observables)
|
||||
which means the request won't go out until something *subscribes* to the observable.
|
||||
That *something* is the [HeroListComponent](#subscribe).
|
||||
|
||||
.l-main-section
|
||||
:marked
|
||||
|
@ -193,15 +196,37 @@ a(id="HeroListComponent")
|
|||
It's best to add that statement early when we're bootstrapping the application.
|
||||
:
|
||||
+makeExample('server-communication/ts/app/main.ts', 'import-rxjs', 'app/main.ts (import rxjs)')(format=".")
|
||||
|
||||
a(id="map")
|
||||
a(id="extract-data")
|
||||
:marked
|
||||
<a id="map"></a>
|
||||
### Map the response object
|
||||
Let's come back to the `HeroService` and look at the `http.get` call again to see why we needed `map()`
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'http-get-v1', 'app/toh/hero.service.ts (http.get)')(format=".")
|
||||
### Process the response object
|
||||
Remember that our `getHeroes` method mapped the `http.get` response object to heroes with an `extractData` helper method:
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'extract-data', 'app/toh/hero.service.ts (extractData)')(format=".")
|
||||
:marked
|
||||
The `response` object does not hold our data in a form we can use directly.
|
||||
It takes an additional step — calling `response.json()` — to transform the bytes from the server into a JSON object.
|
||||
To make it useful in our application we must
|
||||
* check for a bad response
|
||||
* parse the response data into a JSON object
|
||||
.alert.is-important
|
||||
:marked
|
||||
*Beta alert*: error status interception and parsing may be absorbed within `http` when Angular is released.
|
||||
:marked
|
||||
#### Bad status codes
|
||||
A status code outside the 200-300 range is an error from the _application point of view_
|
||||
but it is not an error from the _`http` point of view_.
|
||||
For example, a `404 - Not Found` is a response like any other.
|
||||
The request went out; a response came back; here it is, thank you very much.
|
||||
We'd have an observable error only if `http` failed to operate (e.g., it errored internally).
|
||||
|
||||
Because a status code outside the 200-300 range _is an error_ from the application point of view,
|
||||
we intercept it and throw, moving the observable chain to the error path.
|
||||
|
||||
The `catch` operator that is next in the `getHeroes` observable chain will handle our thrown error.
|
||||
|
||||
#### Parse to JSON
|
||||
The response data are in JSON string form.
|
||||
We must parse that string into JavaScript objects which we do by calling `response.json()`.
|
||||
.l-sub-section
|
||||
:marked
|
||||
This is not Angular's own design.
|
||||
|
@ -228,8 +253,18 @@ a(id="HeroListComponent")
|
|||
It has no interest in what we do to get them.
|
||||
It doesn't care where they come from.
|
||||
And it certainly doesn't want to deal with a response object.
|
||||
|
||||
|
||||
.callout.is-important
|
||||
header HTTP GET is delayed
|
||||
:marked
|
||||
The `http.get` does **not send the request just yet!** This observable is
|
||||
[*cold*](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/gettingstarted/creating.md#cold-vs-hot-observables)
|
||||
which means the request won't go out until something *subscribes* to the observable.
|
||||
That *something* is the [HeroListComponent](#subscribe).
|
||||
|
||||
<a id="error-handling"></a>
|
||||
a(id="error-handling")
|
||||
:marked
|
||||
### Always handle errors
|
||||
|
||||
The eagle-eyed reader may have spotted our use of the `catch` operator in conjunction with a `handleError` method.
|
||||
|
@ -243,8 +278,8 @@ a(id="HeroListComponent")
|
|||
In this simple app we provide rudimentary error handling in both the service and the component.
|
||||
|
||||
We use the Observable `catch` operator on the service level.
|
||||
It takes an error handling function with the failed `Response` object as the argument.
|
||||
Our service handler, `errorHandler`, logs the response to the console,
|
||||
It takes an error handling function with an error object as the argument.
|
||||
Our service handler, `handleError`, logs the response to the console,
|
||||
transforms the error into a user-friendly message, and returns the message in a new, failed observable via `Observable.throw`.
|
||||
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'error-handling', 'app/toh/hero.service.ts')(format=".")
|
||||
|
@ -263,19 +298,7 @@ a(id="HeroListComponent")
|
|||
.l-sub-section
|
||||
:marked
|
||||
Want to see it fail? Reset the api endpoint in the `HeroService` to a bad value. Remember to restore it!
|
||||
<a id="do"></a>
|
||||
<a id="console-log"></a>
|
||||
:marked
|
||||
### Peek at results in the console
|
||||
During development we're often curious about the data returned by the server.
|
||||
Logging to console without disrupting the flow would be nice.
|
||||
|
||||
The Observable `do` operator is perfect for the job.
|
||||
It passes the input through to the output while we do something with a useful side-effect such as writing to console.
|
||||
Slip it into the pipeline between `map` and `catch` like this.
|
||||
+makeExample('server-communication/ts/app/toh/hero.service.ts', 'http-get', 'app/toh/hero.service.ts')(format=".")
|
||||
:marked
|
||||
Remember to comment it out before going to production!
|
||||
|
||||
|
||||
<a id="update"></a>
|
||||
<a id="post"></a>
|
||||
|
@ -327,7 +350,7 @@ code-example(format="." language="javascript").
|
|||
|
||||
:marked
|
||||
### JSON results
|
||||
As with `get`, we extract the data from the response with `json()` and unwrap the hero via the `data` property.
|
||||
As with `getHeroes`, we [extract the data](#extract-data) from the response with `json()` and unwrap the hero via the `data` property.
|
||||
.alert.is-important
|
||||
:marked
|
||||
Know the shape of the data returned by the server.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 12 KiB |
Loading…
Reference in New Issue