docs(toh-6): post-RC5 Dart resync and TS fixes (#2095)

* toh-6: trim spaces from cache file to simplify diff

* toh-6: copy latest over cache before editing latest

* docs(toh-6): post-RC5 Dart resync and TS fixes

Contributes to #2077.

TS-side changes include:
- Merged three versions of `app/app.module{,1,2}.ts` into a single file
and used docregions instead.
- Misnamed files:
  - `rxjs-operators.ts` -> `rxjs-extensions.ts`
  - `hero-search.service.html` -> `hero-search.component.html`
- Fixed BAD FILENAME error.

Lint reports no errors and toh-6 e2e tests pass.
This commit is contained in:
Patrice Chalin 2016-08-12 11:21:16 -07:00 committed by Kathy Walrath
parent ea457825b8
commit dfd46af604
8 changed files with 110 additions and 182 deletions

View File

@ -1,4 +1,4 @@
// #docregion , search
// #docregion
import 'dart:async';
import 'package:angular2/core.dart';
@ -6,6 +6,7 @@ import 'package:angular2/router.dart';
import 'hero.dart';
import 'hero_service.dart';
// #docregion search
import 'hero_search_component.dart';
@Component(

View File

@ -1,6 +1,5 @@
// #docplaster
// #docregion final
// #docregion v1
// #docregion , v1, v2
import 'package:angular2/core.dart';
import 'package:angular2/platform/browser.dart';
import 'package:angular2_tour_of_heroes/app_component.dart';
@ -15,7 +14,7 @@ void main() {
// [provide(Client, useFactory: () => new BrowserClient(), deps: [])]
);
}
// #enddocregion final
// #enddocregion v2,
/*
// #docregion v1
import 'package:http/browser_client.dart';

View File

@ -1,44 +0,0 @@
// #docplaster
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
// Imports for loading & configuring the in-memory web api
import { HttpModule, XHRBackend } from '@angular/http';
import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { HeroesComponent } from './heroes.component';
import { DashboardComponent } from './dashboard.component';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroService } from './hero.service';
@NgModule({
imports: [
BrowserModule,
FormsModule,
routing,
HttpModule
],
declarations: [
AppComponent,
HeroesComponent,
DashboardComponent,
HeroDetailComponent
],
providers: [
HeroService,
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
// #enddocregion final

View File

@ -1,44 +0,0 @@
// #docplaster
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { HeroesComponent } from './heroes.component';
import { DashboardComponent } from './dashboard.component';
import { HeroDetailComponent } from './hero-detail.component';
// #docregion hero-search-declaration
import { HeroSearchComponent } from './hero-search.component';
// #enddocregion hero-search-declaration
import { HeroService } from './hero.service';
@NgModule({
imports: [
BrowserModule,
FormsModule,
routing,
HttpModule
],
// #docregion hero-search-declaration
declarations: [
AppComponent,
HeroesComponent,
DashboardComponent,
HeroDetailComponent,
HeroSearchComponent
],
// #enddocregion hero-search-declaration
providers: [
HeroService
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
// #enddocregion

View File

@ -1,24 +1,31 @@
// #docregion
// #docplaster
// #docregion , v1, v2
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
// #enddocregion v1
// Imports for loading & configuring the in-memory web api
import { HttpModule, XHRBackend } from '@angular/http';
import { XHRBackend } from '@angular/http';
import { InMemoryBackendService, SEED_DATA } from 'angular2-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';
// #docregion v1
import { AppComponent } from './app.component';
import { routing } from './app.routing';
import { HeroesComponent } from './heroes.component';
import { DashboardComponent } from './dashboard.component';
import { HeroDetailComponent } from './hero-detail.component';
import { HeroService } from './hero.service';
// #enddocregion v1, v2
// #docregion search
import { HeroSearchComponent } from './hero-search.component';
// #docregion v1, v2
import { HeroService } from './hero.service';
// #enddocregion search
@NgModule({
imports: [
BrowserModule,
@ -26,20 +33,25 @@ import { HeroService } from './hero.service';
routing,
HttpModule
],
// #docregion search
declarations: [
AppComponent,
HeroesComponent,
DashboardComponent,
HeroDetailComponent,
// #enddocregion v1, v2
HeroSearchComponent
// #docregion v1, v2
],
// #enddocregion search
providers: [
HeroService,
// #enddocregion v1
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: InMemoryDataService } // in-mem server data
// #docregion v1
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
// #enddocregion

View File

@ -6,7 +6,7 @@ block includes
- var _Angular_Http = 'Dart <code>BrowserClient</code>'
- var _httpUrl = 'https://pub.dartlang.org/packages/http'
- var _Angular_http_library = 'Dart <a href="' + _httpUrl + '"><b>http</b></a> package'
- var _HTTP_PROVIDERS = 'BrowserClient'
- var _HttpModule = 'BrowserClient'
- var _JSON_stringify = 'JSON.encode'
block start-server-and-watch
@ -17,15 +17,15 @@ block start-server-and-watch
code-example(language="bash").
pub serve
block http-library
:marked
We'll be using the !{_Angular_http_library}'s
We'll be using the !{_Angular_http_library}'s
`BrowserClient` class to communicate with a server.
### Pubspec updates
We need to add package dependencies for the
We need to add package dependencies for the
`stream_transformers` and !{_Angular_http_library}s.
We also need to add a `resolved_identifiers` entry, to inform the [angular2
@ -45,10 +45,21 @@ block http-providers
:marked
Before our app can use `#{_Http}`, we have to register it as a service provider.
We should be able to access `!{_Http}` services from anywhere in the application.
So we register it in the `bootstrap` call where we
launch the application and its root `AppComponent`.
+makeExcerpt('app/main.ts','v1')
:marked
Notice that we supply `!{_HttpModule}` in a list, as the second parameter to
the `bootstrap` method. This has the same effect as the `providers` list in
`@Component` annotation.
block backend
:marked
We want to replace `BrowserClient`, the service that talks to the remote server,
with the in-memory web API service.
with the in-memory web API service.
Our in-memory web API service, shown below, is implemented using the
`http` library `MockClient` class.
All `http` client implementations share a common `Client` interface, so
@ -77,7 +88,7 @@ block hero-detail-comp-updates
:marked
### Edit in the *HeroDetailComponent*
We already have `HeroDetailComponent` for viewing details about a specific hero.
We already have `HeroDetailComponent` for viewing details about a specific hero.
Supporting edit functionality is a natural extension of the detail view,
so we are able to reuse `HeroDetailComponent` with a few tweaks.
@ -87,9 +98,6 @@ block hero-detail-comp-save-and-goback
block add-new-hero-via-detail-comp
//- N/A
block heroes-comp-directives
//- N/A
block heroes-comp-add
//- N/A
@ -194,10 +202,10 @@ block file-summary
lib/hero_search_component.dart,
lib/hero_search_component.html,
lib/hero_search_service.dart`)
+makeTabs(
`toh-6/dart/pubspec.yaml,
toh-6/dart/web/main.dart`,
`,final`,
null,
`pubspec.yaml,
web/main.dart`)

View File

@ -5,7 +5,7 @@ block includes
- var _Http = 'Http'; // Angular `Http` library name.
- var _Angular_Http = 'Angular <code>Http</code>'
- var _Angular_http_library = 'Angular HTTP library'
- var _HTTP_PROVIDERS = 'HTTP_PROVIDERS'
- var _HttpModule = 'HttpModule'
- var _JSON_stringify = 'JSON.stringify'
:marked
@ -53,25 +53,24 @@ block http-library
block http-providers
:marked
Our app will depend upon the Angular `http` service which itself depends upon other supporting services.
The `HTTP_PROVIDERS` array from `@angular/http` library holds providers for the complete set of http services.
The `HttpModule` from `@angular/http` library holds providers for the complete set of `http` services.
:marked
We should be able to access `!{_Http}` services from anywhere in the application.
So we register them in the `bootstrap` call of <span ngio-ex>main.ts</span> where we
launch the application and its root `AppComponent`.
We should be able to access `http` services from anywhere in the application.
So we register them in the `imports` array of `app.module.ts` where we
bootstrap the application and its root `AppComponent`.
+makeExcerpt('app/main.ts','v1')
+makeExcerpt('app/app.module.ts (v1)')
:marked
Notice that we supply `!{_HTTP_PROVIDERS}` in !{_an} !{_array} as the second parameter to the `bootstrap` method.
This has the same effect as the `providers` !{_array} in `@Component` !{_decorator}.
:marked
Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`.
.l-main-section
:marked
## Simulating the web API
We generally recommend registering application-wide services in the root `AppComponent` *providers*.
Here we're registering in `main` for a special reason.
We recommend registering application-wide services in the root
`!{_AppModuleVsAppComp}` *providers*. <span if-docs="dart">Here we're
registering in `main` for a special reason.</span>
Our application is in the early stages of development and far from ready for production.
We don't even have a web server that can handle requests for heroes.
@ -79,12 +78,13 @@ block http-providers
We're going to *trick* the HTTP client into fetching and saving data from
a mock service, the *in-memory web API*.
<span if-docs="dart"> The application itself doesn't need to know and
shouldn't know about this. So we'll slip the in-memory web API into the
configuration *above* the `AppComponent`.</span>
The application itself doesn't need to know and shouldn't know about this.
So we'll slip the in-memory web API into the configuration *above* the `AppComponent`.
Here is a version of <span ngio-ex>!{_appModuleTsVsMainTs}</span> that performs this trick:
Here is a version of `main` that performs this trick
+makeExcerpt('app/main.ts', 'final')
+makeExcerpt(_appModuleTsVsMainTs, 'v2')
block backend
:marked
@ -133,7 +133,7 @@ block get-heroes-details
*Observables* are a powerful way to manage asynchronous data flows.
We'll learn about [Observables](#observables) later in this chapter.
For *now* we get back on familiar ground by immediately by
For *now* we get back on familiar ground by immediately by
converting that `Observable` to a `Promise` using the `toPromise` operator.
+makeExcerpt('app/hero.service.ts', 'to-promise', '')
:marked
@ -326,19 +326,6 @@ block add-new-hero-via-detail-comp
Now let's fix-up the `HeroesComponent` to support the *add* and *delete* actions used in the template.
Let's start with *add*.
block heroes-comp-directives
:marked
We're using the `HeroDetailComponent` to capture the new hero information.
We have to tell Angular about that by importing the `HeroDetailComponent` and referencing it in the component metadata `directives` array.
+makeExcerpt('app/heroes.component.ts (HeroDetailComponent)', 'hero-detail-component')
.l-sub-section
:marked
These are the same lines that we removed in the previous [Routing](toh-pt5.html) chapter.
We didn't know at the time that we'd need the *HeroDetailComponent* again. So we tidied up.
Now we *must* put these lines back. If we don't, Angular will ignore the `<my-hero-detail>`
tag and pushing the *Add New Hero* button will have no visible effect.
:marked
Implement the click handler for the *Add New Hero* button.
+makeExcerpt('app/heroes.component.ts', 'addHero')
@ -372,7 +359,7 @@ block observables-section-intro
Each `Http` 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
In this section we learn to return the `Observable` directly and discuss when and why that might be
a good thing to do.
### Background
@ -385,15 +372,15 @@ block observables-section-intro
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` to fetch a single chunk of data.
Converting to a promise is often a good choice. We typically ask `http` 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
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.
:marked
But requests aren't always "one and done". We may start one request,
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 *!{_Promise}s*.
Such a _request-cancel-new-request_ sequence is difficult to implement with *!{_Promise}s*.
It's easy with *!{_Observable}s* as we'll see.
### Search-by-name
@ -407,12 +394,12 @@ block observables-section-intro
:marked
The `!{_priv}http.get()` call in `HeroSearchService` is similar to the one
in the `HeroService`, although the URL now has a query string.
<span if-docs="ts">Another notable difference: we no longer call `toPromise`,
<span if-docs="ts">Another notable difference: we no longer call `toPromise`,
we simply return the *observable* instead.</span>
### HeroSearchComponent
Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`.
Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`.
The component template is simple &mdash; just a text box and a list of matching search results.
@ -435,7 +422,7 @@ block observables-section-intro
:marked
#### Search terms
Let's focus on the `!{_priv}searchTerms`:
+makeExcerpt('app/hero-search.component.ts', 'searchTerms', '')
@ -466,7 +453,7 @@ block observable-transformers
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:
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
* `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.
* `distinctUntilChanged` ensures that we only send a request if the filter text changed.
@ -481,21 +468,21 @@ block observable-transformers
(formerly known as "flatMapLatest") is very clever.
Every qualifying key event can trigger an http call.
Even with a 300ms pause between requests, we could have multiple http requests in flight
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 call.
only the observable from the most recent http call.
Results from prior calls are canceled and discarded.
We also short-circuit the http call and return an observable containing an empty array
We also short-circuit the http 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.
:marked
* `catch` intercepts a failed observable.
* `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.
@ -510,7 +497,7 @@ block observable-transformers
:marked
Many authorities say we should do just that.
:marked
We take a different approach in this example.
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.
+makeExample('app/rxjs-extensions.ts')
@ -527,10 +514,12 @@ block observable-transformers
+makeExample('app/dashboard.component.html')
- var _declarations = _docsFor == 'dart' ? 'directives' : 'declarations'
- var declFile = _docsFor == 'dart' ? 'app/dashboard.component.ts' : 'app/app.module.ts'
:marked
And finally, we import the `HeroSearchComponent` and add it to the `directives` !{_array}.
And finally, we import the `HeroSearchComponent` and add it to the `!{_declarations}` !{_array}:
+makeExcerpt('app/dashboard.component.ts', 'search')
+makeExcerpt(declFile, 'search')
:marked
Run the app again, go to the *Dashboard*, and enter some text in the search box.
@ -554,7 +543,8 @@ block filetree
.children
.file app.component.ts
.file app.component.css
.file app.routes.ts
.file app.module.ts
.file app.routing.ts
.file dashboard.component.css
.file dashboard.component.html
.file dashboard.component.ts
@ -566,7 +556,7 @@ block filetree
.file hero-search.component.css (new)
.file hero-search.component.ts (new)
.file hero-search.service.ts (new)
.file rxjs-operators.ts
.file rxjs-extensions.ts
.file hero.service.ts
.file heroes.component.css
.file heroes.component.html
@ -593,12 +583,13 @@ block filetree
- We updated our components to allow adding, editing and deleting of heroes.
- We configured an in-memory web API.
- We learned how to use !{_Observable}s.
Here are the files we added or changed in this chapter.
block file-summary
+makeTabs(
`toh-6/ts/app/app.component.ts,
toh-6/ts/app/app.module.ts,
toh-6/ts/app/heroes.component.ts,
toh-6/ts/app/heroes.component.html,
toh-6/ts/app/heroes.component.css,
@ -606,8 +597,9 @@ block file-summary
toh-6/ts/app/hero-detail.component.html,
toh-6/ts/app/hero.service.ts,
toh-6/ts/app/in-memory-data.service.ts`,
null,
',,,,,,,,',
`app.comp...ts,
app.mod...ts,
heroes.comp...ts,
heroes.comp...html,
heroes.comp...css,
@ -622,11 +614,11 @@ block file-summary
toh-6/ts/app/hero-search.component.ts,
toh-6/ts/app/hero-search.component.html,
toh-6/ts/app/hero-search.component.css,
toh-6/ts/app/rxjs-operators.ts`,
toh-6/ts/app/rxjs-extensions.ts`,
null,
`hero-search.service.ts,
hero-search.component.ts,
hero-search.service.html,
hero-search.component.html,
hero-search.component.css,
rxjs-operators.ts`
rxjs-extensions.ts`
)

View File

@ -5,7 +5,6 @@ block includes
- var _Http = 'Http'; // Angular `Http` library name.
- var _Angular_Http = 'Angular <code>Http</code>'
- var _Angular_http_library = 'Angular HTTP library'
- var _HTTP_PROVIDERS = 'HTTP_PROVIDERS'
- var _HttpModule = 'HttpModule'
- var _JSON_stringify = 'JSON.stringify'
@ -54,23 +53,24 @@ block http-library
block http-providers
:marked
Our app will depend upon the Angular `http` service which itself depends upon other supporting services.
The `HttpModule` from `@angular/http` library holds providers for the complete set of http services.
The `HttpModule` from `@angular/http` library holds providers for the complete set of `http` services.
:marked
We should be able to access `!{_Http}` services from anywhere in the application.
So we register them in the `imports` array of <span ngio-ex>app.module.ts</span> where we
bootstrap the application and its root `AppComponent`.
We should be able to access `http` services from anywhere in the application.
So we register them in the `imports` array of `app.module.ts` where we
bootstrap the application and its root `AppComponent`.
+makeExample('app/app.module.2.ts','', 'app.module.ts (v.1)')
+makeExcerpt('app/app.module.ts (v1)')
:marked
Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`.
:marked
Notice that we supply `!{_HttpModule}` as part of the *imports* !{_array} in root NgModule `AppModule`.
.l-main-section
:marked
## Simulating the web API
We recommend registering application-wide services in the root `NgModule` *providers*.
We recommend registering application-wide services in the root
`!{_AppModuleVsAppComp}` *providers*. <span if-docs="dart">Here we're
registering in `main` for a special reason.</span>
Our application is in the early stages of development and far from ready for production.
We don't even have a web server that can handle requests for heroes.
@ -78,9 +78,13 @@ block http-providers
We're going to *trick* the HTTP client into fetching and saving data from
a mock service, the *in-memory web API*.
<span if-docs="dart"> The application itself doesn't need to know and
shouldn't know about this. So we'll slip the in-memory web API into the
configuration *above* the `AppComponent`.</span>
Here is a version of `app.module.ts` that performs this trick
+makeExample('app/app.module.1.ts', '', 'app.module.ts (final)')
Here is a version of <span ngio-ex>!{_appModuleTsVsMainTs}</span> that performs this trick:
+makeExcerpt(_appModuleTsVsMainTs, 'v2')
block backend
:marked
@ -510,11 +514,12 @@ block observable-transformers
+makeExample('app/dashboard.component.html')
- var _declarations = _docsFor == 'dart' ? 'directives' : 'declarations'
- var declFile = _docsFor == 'dart' ? 'app/dashboard.component.ts' : 'app/app.module.ts'
:marked
And finally, we import the `HeroSearchComponent` and add it to the `declarations` !{_array} in
`app.module.ts`.
And finally, we import the `HeroSearchComponent` and add it to the `!{_declarations}` !{_array}:
+makeExcerpt('app/app.module.2.ts', 'hero-search-declaration')
+makeExcerpt(declFile, 'search')
:marked
Run the app again, go to the *Dashboard*, and enter some text in the search box.
@ -551,7 +556,7 @@ block filetree
.file hero-search.component.css (new)
.file hero-search.component.ts (new)
.file hero-search.service.ts (new)
.file rxjs-operators.ts
.file rxjs-extensions.ts
.file hero.service.ts
.file heroes.component.css
.file heroes.component.html
@ -609,12 +614,11 @@ block file-summary
toh-6/ts/app/hero-search.component.ts,
toh-6/ts/app/hero-search.component.html,
toh-6/ts/app/hero-search.component.css,
toh-6/ts/app/rxjs-operators.ts`,
toh-6/ts/app/rxjs-extensions.ts`,
null,
`hero-search.service.ts,
hero-search.component.ts,
hero-search.service.html,
hero-search.component.html,
hero-search.component.css,
hero-search.component.css,
rxjs-operators.ts`
rxjs-extensions.ts`
)