`,
providers: [ WikipediaService ]
})
export class WikiComponent {
- title = 'Wikipedia Demo';
- fetches = 'Fetches after each keystroke';
items: Observable;
+ constructor (private wikipediaService: WikipediaService) { }
+
search (term: string) {
this.items = this.wikipediaService.search(term);
}
-
- constructor (private wikipediaService: WikipediaService) { }
}
diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts
index 25911b0d37..5cbcb7d707 100644
--- a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts
+++ b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.1.ts
@@ -3,6 +3,8 @@
import { Injectable } from '@angular/core';
import { Jsonp } from '@angular/http';
+import 'rxjs/add/operator/map';
+
@Injectable()
export class WikipediaService {
constructor(private jsonp: Jsonp) { }
diff --git a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts
index 742dfed1b9..a38167d1c6 100644
--- a/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts
+++ b/public/docs/_examples/server-communication/ts/app/wiki/wikipedia.service.ts
@@ -2,6 +2,8 @@
import { Injectable } from '@angular/core';
import { Jsonp, URLSearchParams } from '@angular/http';
+import 'rxjs/add/operator/map';
+
@Injectable()
export class WikipediaService {
constructor(private jsonp: Jsonp) {}
diff --git a/public/docs/_examples/style-guide/ts/04-11/app/core/index.ts b/public/docs/_examples/style-guide/ts/04-11/app/core/index.ts
index 7d2092f804..098f40c7d5 100644
--- a/public/docs/_examples/style-guide/ts/04-11/app/core/index.ts
+++ b/public/docs/_examples/style-guide/ts/04-11/app/core/index.ts
@@ -1,5 +1,4 @@
// #docregion
export * from './logger.service';
-export * from './rxjs-extensions';
export * from './spinner/spinner.service';
export * from './nav/nav.component';
diff --git a/public/docs/_examples/style-guide/ts/04-11/app/core/rxjs-extensions.ts b/public/docs/_examples/style-guide/ts/04-11/app/core/rxjs-extensions.ts
deleted file mode 100644
index 870dd7af2b..0000000000
--- a/public/docs/_examples/style-guide/ts/04-11/app/core/rxjs-extensions.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-// #docregion
-import 'rxjs/add/operator/catch';
-import 'rxjs/add/operator/do';
-import 'rxjs/add/operator/finally';
-import 'rxjs/add/operator/map';
-import 'rxjs/add/operator/mergeMap';
-import 'rxjs/add/observable/of';
diff --git a/public/docs/_examples/style-guide/ts/05-15/app/heroes/hero-list/hero-list.component.avoid.ts b/public/docs/_examples/style-guide/ts/05-15/app/heroes/hero-list/hero-list.component.avoid.ts
index b66bb9e81f..c323ba2b1c 100644
--- a/public/docs/_examples/style-guide/ts/05-15/app/heroes/hero-list/hero-list.component.avoid.ts
+++ b/public/docs/_examples/style-guide/ts/05-15/app/heroes/hero-list/hero-list.component.avoid.ts
@@ -3,7 +3,11 @@
import { OnInit } from '@angular/core';
import { Http, Response } from '@angular/http';
+
import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/finally';
+import 'rxjs/add/operator/map';
import { Hero } from '../shared/hero.model';
diff --git a/public/docs/_examples/style-guide/ts/05-15/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/05-15/app/heroes/shared/hero.service.ts
index 3f83d92fe8..72d07bbed4 100644
--- a/public/docs/_examples/style-guide/ts/05-15/app/heroes/shared/hero.service.ts
+++ b/public/docs/_examples/style-guide/ts/05-15/app/heroes/shared/hero.service.ts
@@ -1,6 +1,8 @@
// #docregion
import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Rx';
+
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/observable/of';
import { Hero } from './hero.model';
diff --git a/public/docs/_examples/style-guide/ts/07-03/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/07-03/app/heroes/shared/hero.service.ts
index 3f83d92fe8..72d07bbed4 100644
--- a/public/docs/_examples/style-guide/ts/07-03/app/heroes/shared/hero.service.ts
+++ b/public/docs/_examples/style-guide/ts/07-03/app/heroes/shared/hero.service.ts
@@ -1,6 +1,8 @@
// #docregion
import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Rx';
+
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/observable/of';
import { Hero } from './hero.model';
diff --git a/public/docs/_examples/style-guide/ts/07-04/app/heroes/shared/hero.service.ts b/public/docs/_examples/style-guide/ts/07-04/app/heroes/shared/hero.service.ts
index 3f83d92fe8..72d07bbed4 100644
--- a/public/docs/_examples/style-guide/ts/07-04/app/heroes/shared/hero.service.ts
+++ b/public/docs/_examples/style-guide/ts/07-04/app/heroes/shared/hero.service.ts
@@ -1,6 +1,8 @@
// #docregion
import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Rx';
+
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/observable/of';
import { Hero } from './hero.model';
diff --git a/public/docs/_examples/toh-6/ts/app/app.module.ts b/public/docs/_examples/toh-6/ts/app/app.module.ts
index c0933e4697..58eeb10c54 100644
--- a/public/docs/_examples/toh-6/ts/app/app.module.ts
+++ b/public/docs/_examples/toh-6/ts/app/app.module.ts
@@ -1,9 +1,5 @@
// #docplaster
// #docregion
-// #docregion rxjs-extensions
-import './rxjs-extensions';
-// #enddocregion rxjs-extensions
-
// #docregion v1, v2
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
diff --git a/public/docs/_examples/toh-6/ts/app/hero-search.component.ts b/public/docs/_examples/toh-6/ts/app/hero-search.component.ts
index 78c490ef93..949ef897db 100644
--- a/public/docs/_examples/toh-6/ts/app/hero-search.component.ts
+++ b/public/docs/_examples/toh-6/ts/app/hero-search.component.ts
@@ -2,9 +2,20 @@
// #docregion
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
+
+// #docregion rxjs-imports
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
+// Observable class extensions
+import 'rxjs/add/observable/of';
+
+// Observable operators
+import 'rxjs/add/operator/catch';
+import 'rxjs/add/operator/debounceTime';
+import 'rxjs/add/operator/distinctUntilChanged';
+// #enddocregion rxjs-imports
+
import { HeroSearchService } from './hero-search.service';
import { Hero } from './hero';
@@ -37,15 +48,15 @@ export class HeroSearchComponent implements OnInit {
ngOnInit(): void {
this.heroes = this.searchTerms
- .debounceTime(300) // wait for 300ms pause in events
+ .debounceTime(300) // wait 300ms after each keystroke before considering the term
.distinctUntilChanged() // ignore if next search term is same as previous
- .switchMap(term => term // switch to new observable each time
+ .switchMap(term => term // switch to new observable each time the term changes
// return the http search observable
? this.heroSearchService.search(term)
- // or the observable of empty heroes if no search term
+ // or the observable of empty heroes if there was no search term
: Observable.of([]))
.catch(error => {
- // TODO: real error handling
+ // TODO: add real error handling
console.log(error);
return Observable.of([]);
});
diff --git a/public/docs/_examples/toh-6/ts/app/hero-search.service.ts b/public/docs/_examples/toh-6/ts/app/hero-search.service.ts
index ae2e47670a..d24e0fba41 100644
--- a/public/docs/_examples/toh-6/ts/app/hero-search.service.ts
+++ b/public/docs/_examples/toh-6/ts/app/hero-search.service.ts
@@ -1,7 +1,9 @@
// #docregion
-import { Injectable } from '@angular/core';
-import { Http, Response } from '@angular/http';
-import { Observable } from 'rxjs';
+import { Injectable } from '@angular/core';
+import { Http } from '@angular/http';
+
+import { Observable } from 'rxjs/Observable';
+import 'rxjs/add/operator/map';
import { Hero } from './hero';
@@ -13,6 +15,6 @@ export class HeroSearchService {
search(term: string): Observable {
return this.http
.get(`app/heroes/?name=${term}`)
- .map((r: Response) => r.json().data as Hero[]);
+ .map(response => response.json().data as Hero[]);
}
}
diff --git a/public/docs/_examples/toh-6/ts/app/rxjs-extensions.ts b/public/docs/_examples/toh-6/ts/app/rxjs-extensions.ts
deleted file mode 100644
index a0facfe03e..0000000000
--- a/public/docs/_examples/toh-6/ts/app/rxjs-extensions.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// #docregion
-// 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';
diff --git a/public/docs/ts/latest/guide/server-communication.jade b/public/docs/ts/latest/guide/server-communication.jade
index 72bfdf5aed..d82c9fdea2 100644
--- a/public/docs/ts/latest/guide/server-communication.jade
+++ b/public/docs/ts/latest/guide/server-communication.jade
@@ -55,12 +55,6 @@ block demos-list
The root `AppComponent` orchestrates these demos:
+makeExample('server-communication/ts/app/app.component.ts', null, 'app/app.component.ts')
-+ifDocsFor('ts')
- :marked
- There is nothing remarkable here _except_ for the import of RxJS operators, which is
- described [later](#rxjs).
- +makeExample('server-communication/ts/app/app.component.ts', 'import-rxjs')(format='.')
-
.l-main-section#http-providers
:marked
# Providing HTTP services
@@ -196,7 +190,7 @@ a#HeroService
:marked
If you are familiar with asynchronous methods in modern JavaScript, you might expect the `get` method to return a
- [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
+ promise.
You'd expect to chain a call to `then()` and extract the heroes.
Instead you're calling a `map()` method.
Clearly this is not a promise.
@@ -207,47 +201,24 @@ a#HeroService
.l-main-section
:marked
## RxJS library
- [RxJS](https://github.com/ReactiveX/RxJS) ("Reactive Extensions") is a 3rd party library, endorsed by Angular,
- that implements the [*asynchronous observable*](https://www.youtube.com/watch?v=UHI0AzD_WfY "Rob Wormald on observables") pattern.
+ RxJS
+ is a third party library, endorsed by Angular, that implements the
+ asynchronous observable pattern.
- All of the Developer Guide samples have installed the RxJS npm package and loaded via `system.js`
+ All of the Developer Guide samples have installed the RxJS npm package
because observables are used widely in Angular applications.
-
- The app needs it when working with the HTTP client.
- Additionally, you must take a critical extra step to make RxJS observables usable.
+ _This_ app needs it when working with the HTTP client.
+ But you must take a critical extra step to make RxJS observables usable:
+ you must import the RxJS operators individually.
### Enable RxJS operators
The RxJS library is large.
Size matters when building a production application and deploying it to mobile devices.
You should include only necessary features.
- Accordingly, Angular exposes a stripped down version of `Observable` in the `rxjs/Observable`
- module that lacks most of the operators such as the `map` method you
- called above in `getHeroes`.
-
- It's up to you to add the operators you need.
-
- You could add _every_ RxJS operator with a single import statement.
- While that is the easiest thing to do, you'd pay a penalty in extended launch time
- and application size because the full library is so big.
-
- Since this app only uses a few operators, it's better to import each `Observable`
- operator and static class method, one-by-one, for a custom *Observable*
- implementation tuned
- precisely to the app's requirements. Put the `import` statements in one `app/rxjs-operators.ts` file.
- +makeExample('server-communication/ts/app/rxjs-operators.ts', null, 'app/rxjs-operators.ts')(format=".")
- :marked
- If you forget an operator, the TypeScript compiler warns that it's missing and you'll update this file.
- .l-sub-section
- :marked
- The app doesn't need _all_ of these particular operators in the `HeroService` — just `map`, `catch` and `throw`.
- The other operators are for later, in the *Wiki* example [below](#more-observables).
- :marked
- Finally, import `rxjs-operator` into `app.component.ts`:
- +makeExample('server-communication/ts/app/app.component.ts', 'import-rxjs', 'app/app.component.ts (import rxjs)')(format=".")
-
- :marked
- Now continue to the next section to return to the `HeroService`.
+ Each code file should add the operators it needs by importing from an RxJS library.
+ The `getHeroes` method needs the `map` and `catch` operators so it imports them like this.
+ +makeExample('server-communication/ts/app/toh/hero.service.ts', 'rxjs-imports', 'app/app.component.ts (import rxjs)')(format=".")
.l-main-section
a#extract-data
@@ -521,15 +492,13 @@ block wikipedia-jsonp+
:marked
### The WikiComponent
- Now that you have a service that can query the Wikipedia API
- turn to the component (template and class) that takes user input and displays search results.
- +makeExample('server-communication/ts/app/wiki/wiki.component.html', null, 'app/wiki/wiki.component.html')
+ Now that you have a service that can query the Wikipedia API,
+ turn your attention to the component (template and class) that takes user input and displays search results.
+makeExample('server-communication/ts/app/wiki/wiki.component.ts', null, 'app/wiki/wiki.component.ts')
:marked
The template presents an `` element *search box* to gather search terms from the user,
and calls a `search(term)` method after each `keyup` event.
- +makeExample('server-communication/ts/app/wiki/wiki.component.html', 'keyup', 'wiki/wiki.component.html')(format='.')
- :marked
+
The component's `search(term)` method delegates to the `WikipediaService`, which returns an
observable array of string results (`Observable`).
Instead of subscribing to the observable inside the component, as in the `HeroListComponent`,
@@ -549,7 +518,7 @@ block wikipedia-jsonp+
It is inefficient, and potentially expensive on mobile devices with limited data plans.
### 1. Wait for the user to stop typing
- Presently, the code calls the server after every key stroke.
+ Presently, the code calls the server after every keystroke.
It should only make requests when the user *stops typing* .
Here's how it will work after refactoring:
figure.image-display
@@ -569,67 +538,71 @@ block wikipedia-jsonp+
The application issues two search requests, one for *angular* and one for *http*.
Which response arrives first? It's unpredictable.
- A load balancer could dispatch the requests to two different servers with different response times.
- The results from the first *angular* request might arrive after the later *http* results.
- The user will be confused if the *angular* results display to the *http* query.
-
When there are multiple requests in-flight, the app should present the responses
- in the original request order. That won't happen if *angular* results arrive last.
+ in the original request order.
+ In this example, the app must always display the results for the *http* search
+ no matter which response arrives first.
## More fun with observables
- You can address these problems and improve the app with the help of some nifty observable operators.
You could make changes to the `WikipediaService`, but for a better
- user experience, create a copy of the `WikiComponent` instead and make it smarter.
- Here's the `WikiSmartComponent` which uses the same template.
+ user experience, create a copy of the `WikiComponent` instead and make it smarter,
+ with the help of some nifty observable operators.
- +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', null, 'app/wiki/wiki-smart.component.ts')
+ Here's the `WikiSmartComponent`, shown next to the original `WikiComponent`
+
+ +makeTabs(
+ `server-communication/ts/app/wiki/wiki-smart.component.ts,
+ server-communication/ts/app/wiki/wiki.component.ts`,
+ null,
+ `app/wiki/wiki-smart.component.ts,
+ app/wiki/wiki.component.ts`
+ )
:marked
+ While the templates are virtually identical,
+ there's a lot more RxJS in the "smart" version,
+ starting with `debounceTime`, `distinctUntilChanged`, and `switchMap` operators,
+ imported as [described above](#rxjs).
+
### Create a stream of search terms
- The template still binds to the search box `keyup` event and passes the complete search box value
- into the component's `search` method after every user keystroke.
- +makeExample('server-communication/ts/app/wiki/wiki.component.html', 'keyup', 'app/wiki/wiki.component.html (input)')(format='.')
- :marked
- The `WikiSmartComponent` turns the search box values into an observable _stream of search terms_
- with the help of a `Subject` which you import from the RxJS observable library:
- +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'import-subject', 'app/wiki/wiki-smart.component.ts')
+ The `WikiComponent` passes a new search term directly to the `WikipediaService` after every keystroke.
+
+ The `WikiSmartComponent` class turns the user's keystrokes into an observable _stream of search terms_
+ with the help of a `Subject`, which you import from RxJS:
+ +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'import-subject')(format='.')
:marked
The component creates a `searchTermStream` as a `Subject` of type `string`.
The `search` method adds each new search box value to that stream via the subject's `next` method.
- +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'subject', 'app/wiki/wiki-smart.component.ts')(format='.')
+ +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'subject')(format='.')
:marked
### Listen for search terms
-
- Earlier, you passed each search term directly to the service and bound the template to the service results.
-
- Now you listen to the *stream of search terms*, manipulating the stream before it reaches the `WikipediaService`.
- +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'observable-operators',
- 'app/wiki/wiki-smart.component.ts')(format='.')
+
+ The `WikiSmartComponent` listens to the *stream of search terms* and
+ processes that stream _before_ calling the service.
+ +makeExample('server-communication/ts/app/wiki/wiki-smart.component.ts', 'observable-operators')(format='.')
:marked
- Wait for the user to stop typing for at least 300 milliseconds
- ([_debounceTime_](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/debounce.md)).
- Only changed search values make it through to the service
- ([_distinctUntilChanged_](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/distinctuntilchanged.md)).
+ * debounceTime
+ waits for the user to stop typing for at least 300 milliseconds.
- The `WikipediaService` returns a separate observable of string arrays (`Observable`) for each request.
- There could be multiple requests *in-flight*, all awaiting the server's reply,
- which means multiple *observables-of-strings* could arrive at any moment in any order.
+ * distinctUntilChanged
+ ensures that the service is called only when the new search term is different from the previous search term.
- The [_switchMap_](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/flatmaplatest.md)
- (formerly known as `flatMapLatest`) returns a new observable that combines these `WikipediaService` observables,
+ * The switchMap
+ calls the `WikipediaService` with a fresh, debounced search term and coordinates the stream(s) of service response.
+
+ The role of `switchMap` is particularly important.
+ The `WikipediaService` returns a separate observable of string arrays (`Observable`) for each search request.
+ The user could issue multiple requests before a slow server has had time to reply,
+ which means a backlog of response observables could arrive at the client, at any moment, in any order.
+
+ The `switchMap` returns its own observable that _combines_ all `WikipediaService` response observables,
re-arranges them in their original request order,
and delivers to subscribers only the most recent search results.
- The displayed list of search results stays in sync with the user's sequence of search terms.
- .l-sub-section
- :marked
- You added the `debounceTime`, `distinctUntilChanged`, and `switchMap` operators to the RxJS `Observable` class
- in `rxjs-operators` as [described above](#rxjs).
-
a#xsrf
.l-main-section
:marked
diff --git a/public/docs/ts/latest/tutorial/toh-pt6.jade b/public/docs/ts/latest/tutorial/toh-pt6.jade
index 188d404222..2dd073e1ba 100644
--- a/public/docs/ts/latest/tutorial/toh-pt6.jade
+++ b/public/docs/ts/latest/tutorial/toh-pt6.jade
@@ -168,6 +168,10 @@ block get-heroes-details
+makeExcerpt('app/hero.service.ts', 'rxjs', '')
+ .l-sub-section
+ :marked
+ You'll add more operators, and learn why you must do so, [later in this tutorial](#rxjs-imports).
+
:marked
### Extracting the data in the *then* callback
@@ -377,8 +381,9 @@ block observables-section-intro
### Background
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](http://reactivex.io/rxjs/) library.
+ Angular core has basic support for observables.
+ We developers augment that support with operators and extensions from the
+ RxJS library.
We'll see how shortly.
Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`.
@@ -406,8 +411,15 @@ 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.
- Another notable difference: we no longer call `toPromise`,
- we simply return the *observable* instead.
+
+ A more important difference: we no longer call `toPromise`.
+ Instead we return the *observable* from the the `htttp.get`,
+ after chaining it to another RxJS operator, map,
+ to extract heroes from the response data.
+
+ RxJS operator chaining makes response processing easy and readable.
+ See the [discuss below about operators](#rxjs-imports).
+
### HeroSearchComponent
@@ -498,26 +510,24 @@ block observable-transformers
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.
+ a#rxjs-imports
+ :marked
### Import RxJS operators
- The RxJS operators are not available in Angular's base `Observable` implementation.
- We have to extend `Observable` by *importing* them.
+ Most RxJS operators are not included in Angular's base `Observable` implementation.
+ The base implementation includes only what Angular itself requires.
- We could extend `Observable` with just the operators we need here by
- including the pertinent `import` statements at the top of this file.
+ If we want more RxJS features, we have to extend `Observable` by *importing* the libraries in which they are defined.
+ Here are all the RxJS imports _this_ component needs:
- .l-sub-section
- :marked
- Many authorities say we should do just that.
- :marked
- 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')(format='.')
+ +makeExample('app/hero-search.component.ts','rxjs-imports','app/hero-search.component.ts (rxjs imports)')(format='.')
:marked
- We load them all at once by importing `rxjs-extensions` at the top of `AppModule`.
-
- +makeExcerpt('app/app.module.ts', 'rxjs-extensions')(format='.')
+ The `import 'rxjs/add/...'` syntax may be unfamiliar.
+ It's missing the usual list of symbols between the braces: `{...}`.
+
+ We don't need the operator symbols themselves.
+ In each case, the mere act of importing the library
+ loads and executes the library's script file which, in turn, adds the operator to the `Observable` class.
:marked
### Add the search component to the dashboard
@@ -570,7 +580,6 @@ block filetree
.file hero-search.component.css (new)
.file hero-search.component.ts (new)
.file hero-search.service.ts (new)
- .file rxjs-extensions.ts
.file hero.service.ts
.file heroes.component.css
.file heroes.component.html
@@ -625,14 +634,12 @@ block file-summary
`toh-6/ts/app/hero-search.service.ts,
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-extensions.ts`,
+ toh-6/ts/app/hero-search.component.css`,
null,
`hero-search.service.ts,
hero-search.component.ts,
hero-search.component.html,
- hero-search.component.css,
- rxjs-extensions.ts`
+ hero-search.component.css`
)
.l-sub-section