parent
28058b784b
commit
9f7bd8f618
|
@ -313,7 +313,6 @@ It takes two more parameters:
|
|||
1. `httpOptions` - the method options which, in this case, [specify required headers](#adding-headers).
|
||||
|
||||
Of course it catches errors in much the same manner [described above](#error-details).
|
||||
It also _taps_ the returned observable in order to log the successful POST.
|
||||
|
||||
The `HeroesComponent` initiates the actual POST operation by subscribing to
|
||||
the `Observable` returned by this service method.
|
||||
|
@ -347,18 +346,14 @@ the `Observable` returned by this service method.
|
|||
title="app/heroes/heroes.component.ts (deleteHero)" linenums="false">
|
||||
</code-example>
|
||||
|
||||
The component isn't expecting a result from the delete operation, so it subscribes without a callback. Even though you are not using the result, you still have to subscribe. Calling the `subscribe()` method _executes_ the observable, which is what initiates the DELETE request.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
You must call _subscribe()_ or nothing happens!
|
||||
You must call _subscribe()_ or nothing happens. Just calling `HeroService.deleteHero()` **does not initiate the DELETE request.**
|
||||
|
||||
</div>
|
||||
|
||||
The component isn't expecting a result from the delete operation and
|
||||
subscribes without a callback.
|
||||
The bare `.subscribe()` _seems_ pointless.
|
||||
|
||||
In fact, it is essential.
|
||||
Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request.**
|
||||
|
||||
<code-example
|
||||
path="http/src/app/heroes/heroes.component.ts"
|
||||
|
@ -366,7 +361,7 @@ Merely calling `HeroService.deleteHero()` **does not initiate the DELETE request
|
|||
</code-example>
|
||||
|
||||
{@a always-subscribe}
|
||||
### Always _subscribe_!
|
||||
**Always _subscribe_!**
|
||||
|
||||
An `HttpClient` method does not begin its HTTP request until you call `subscribe()` on the observable returned by that method. This is true for _all_ `HttpClient` _methods_.
|
||||
|
||||
|
@ -378,8 +373,7 @@ The [`AsyncPipe`](api/common/AsyncPipe) subscribes (and unsubscribes) for you au
|
|||
|
||||
All observables returned from `HttpClient` methods are _cold_ by design.
|
||||
Execution of the HTTP request is _deferred_, allowing you to extend the
|
||||
observable with additional operations such as `tap` and `catchError`
|
||||
before anything actually happens.
|
||||
observable with additional operations such as `tap` and `catchError` before anything actually happens.
|
||||
|
||||
Calling `subscribe(...)` triggers execution of the observable and causes
|
||||
`HttpClient` to compose and send the HTTP request to the server.
|
||||
|
@ -417,7 +411,7 @@ in order to initiate the request.
|
|||
|
||||
## Advanced usage
|
||||
|
||||
The above sections detail how to use the basic HTTP functionality in `@angular/common/http`, but sometimes you need to do more than make simple requests and get data back.
|
||||
We have discussed the basic HTTP functionality in `@angular/common/http`, but sometimes you need to do more than make simple requests and get data back.
|
||||
|
||||
### Configuring the request
|
||||
|
||||
|
@ -454,7 +448,7 @@ Here is a `searchHeroes` method that queries for heroes whose names contain the
|
|||
region="searchHeroes" linenums="false">
|
||||
</code-example>
|
||||
|
||||
If there is a search term, the code constructs an options object with an HTML URL encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
||||
If there is a search term, the code constructs an options object with an HTML URL-encoded search parameter. If the term were "foo", the GET request URL would be `api/heroes/?name=foo`.
|
||||
|
||||
The `HttpParms` are immutable so you'll have to use the `set()` method to update the options.
|
||||
|
||||
|
@ -463,7 +457,7 @@ The `HttpParms` are immutable so you'll have to use the `set()` method to update
|
|||
The sample includes an _npm package search_ feature.
|
||||
|
||||
When the user enters a name in a search-box, the `PackageSearchComponent` sends
|
||||
a search request for a package with that name to the NPM web api.
|
||||
a search request for a package with that name to the NPM web API.
|
||||
|
||||
Here's a pertinent excerpt from the template:
|
||||
|
||||
|
@ -486,7 +480,7 @@ That's easy to implement with RxJS operators, as shown in this excerpt.
|
|||
</code-example>
|
||||
|
||||
The `searchText$` is the sequence of search-box values coming from the user.
|
||||
It's defined as an RxJS `Subject`, which means it is an `Observable`
|
||||
It's defined as an RxJS `Subject`, which means it is a multicasting `Observable`
|
||||
that can also produce values for itself by calling `next(value)`,
|
||||
as happens in the `search()` method.
|
||||
|
||||
|
@ -820,7 +814,7 @@ Some folks describe it as a "_one and done_" observable.
|
|||
But an interceptor can change this to an _observable_ that emits more than once.
|
||||
|
||||
A revised version of the `CachingInterceptor` optionally returns an _observable_ that
|
||||
immediately emits the cached response, sends the request to the npm web api anyway,
|
||||
immediately emits the cached response, sends the request to the NPM web API anyway,
|
||||
and emits again later with the updated search results.
|
||||
|
||||
<code-example
|
||||
|
|
|
@ -940,8 +940,7 @@ with that hero's data values.
|
|||
|
||||
A refresh button clears the hero list and the current selected hero before refetching the heroes.
|
||||
|
||||
Notice that `hero-list.component.ts` imports `Observable` and `finally` while `hero.service.ts` imports `Observable`, `of`,
|
||||
and `delay` from `rxjs`.
|
||||
Notice that `hero-list.component.ts` imports `Observable` and the `finally` operator, while `hero.service.ts` imports `Observable`, `of` and the `delay` operator from `rxjs`.
|
||||
|
||||
The remaining `HeroListComponent` and `HeroService` implementation details are beyond the scope of this tutorial.
|
||||
However, the techniques involved are covered elsewhere in the documentation, including the _Tour of Heroes_
|
||||
|
|
|
@ -340,9 +340,9 @@ It has a great deal of useful information including:
|
|||
|
||||
Two older properties are still available. They are less capable than their replacements, discouraged, and may be deprecated in a future Angular version.
|
||||
|
||||
**`params`** — An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. Use `paramMap` instead.
|
||||
**`params`**—An `Observable` that contains the required and [optional parameters](#optional-route-parameters) specific to the route. Use `paramMap` instead.
|
||||
|
||||
**`queryParams`** — An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
|
||||
**`queryParams`**—An `Observable` that contains the [query parameters](#query-parameters) available to all routes.
|
||||
Use `queryParamMap` instead.
|
||||
|
||||
</div>
|
||||
|
@ -1619,8 +1619,7 @@ They are distributed across two modules, `AppRoutingModule` and `HeroesRoutingMo
|
|||
Each routing module augments the route configuration _in the order of import_.
|
||||
If you list `AppRoutingModule` first, the wildcard route will be registered
|
||||
_before_ the hero routes.
|
||||
The wildcard route — which matches _every_ URL —
|
||||
will intercept the attempt to navigate to a hero route.
|
||||
The wildcard route—which matches _every_ URL—will intercept the attempt to navigate to a hero route.
|
||||
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -2060,7 +2059,7 @@ The path for the "Heroes" route doesn't have an `:id` token.
|
|||
|
||||
The optional route parameters are not separated by "?" and "&" as they would be in the URL query string.
|
||||
They are **separated by semicolons ";"**
|
||||
This is *matrix URL* notation — something you may not have seen before.
|
||||
This is *matrix URL* notation—something you may not have seen before.
|
||||
|
||||
|
||||
<div class="l-sub-section">
|
||||
|
@ -3149,7 +3148,7 @@ Here's a demo `AuthService`:
|
|||
Although it doesn't actually log in, it has what you need for this discussion.
|
||||
It has an `isLoggedIn` flag to tell you whether the user is authenticated.
|
||||
Its `login` method simulates an API call to an external service by returning an
|
||||
Observable that resolves successfully after a short pause.
|
||||
observable that resolves successfully after a short pause.
|
||||
The `redirectUrl` property will store the attempted URL so you can navigate to it after authenticating.
|
||||
|
||||
Revise the `AuthGuard` to call it.
|
||||
|
@ -3459,13 +3458,11 @@ Be explicit. Implement the `Resolve` interface with a type of `Crisis`.
|
|||
Inject the `CrisisService` and `Router` and implement the `resolve()` method.
|
||||
That method could return a `Promise`, an `Observable`, or a synchronous return value.
|
||||
|
||||
The `CrisisService.getCrisis` method returns an Observable.
|
||||
Return that observable to prevent the route from loading until the data is fetched.
|
||||
The `Router` guards require an Observable to `complete`, meaning it has emitted all
|
||||
The `CrisisService.getCrisis` method returns an observable, in order to prevent the route from loading until the data is fetched.
|
||||
The `Router` guards require an observable to `complete`, meaning it has emitted all
|
||||
of its values. You use the `take` operator with an argument of `1` to ensure that the
|
||||
Observable completes after retrieving the first value from the Observable returned by the
|
||||
`getCrisis` method.
|
||||
If it doesn't return a valid `Crisis`, navigate the user back to the `CrisisListComponent`,
|
||||
observable completes after retrieving the first value from the observable returned by the
|
||||
`getCrisis` method. If it doesn't return a valid `Crisis`, navigate the user back to the `CrisisListComponent`,
|
||||
canceling the previous in-flight navigation to the `CrisisDetailComponent`.
|
||||
|
||||
Import this resolver in the `crisis-center-routing.module.ts`
|
||||
|
@ -3502,8 +3499,8 @@ The router looks for that method and calls it if found.
|
|||
Don't worry about all the ways that the user could navigate away.
|
||||
That's the router's job. Write this class and let the router take it from there.
|
||||
|
||||
1. The Observable provided to the Router _must_ complete.
|
||||
If the Observable does not complete, the navigation will not continue.
|
||||
1. The observable provided to the Router _must_ complete.
|
||||
If the observable does not complete, the navigation will not continue.
|
||||
|
||||
The relevant *Crisis Center* code for this milestone follows.
|
||||
|
||||
|
@ -3928,7 +3925,7 @@ The router calls the `preload` method with two arguments:
|
|||
1. The route to consider.
|
||||
1. A loader function that can load the routed module asynchronously.
|
||||
|
||||
An implementation of `preload`must return an `Observable`.
|
||||
An implementation of `preload` must return an `Observable`.
|
||||
If the route should preload, it returns the observable returned by calling the loader function.
|
||||
If the route should _not_ preload, it returns an `Observable` of `null`.
|
||||
|
||||
|
|
|
@ -262,13 +262,12 @@ test any service with a dependency.
|
|||
|
||||
<div class="alert is-important">
|
||||
|
||||
The `HeroService` methods return _Observables_.
|
||||
_Subscribe_ to the method observable to (a) cause it to execute and (b)
|
||||
The `HeroService` methods return `Observables`. You must
|
||||
_subscribe_ to an observable to (a) cause it to execute and (b)
|
||||
assert that the method succeeds or fails.
|
||||
|
||||
The `subscribe()` method takes a success and fail callback.
|
||||
The `subscribe()` method takes a success (`next`) and fail (`error`) callback.
|
||||
Make sure you provide _both_ callbacks so that you capture errors.
|
||||
|
||||
Neglecting to do so produces an asynchronous uncaught observable error that
|
||||
the test runner will likely attribute to a completely different test.
|
||||
|
||||
|
@ -1024,9 +1023,9 @@ Focus on the spy.
|
|||
region="spy">
|
||||
</code-example>
|
||||
|
||||
The spy is designed such that any call to `getQuote` receives an Observable with a test quote.
|
||||
The spy is designed such that any call to `getQuote` receives an observable with a test quote.
|
||||
Unlike the real `getQuote()` method, this spy bypasses the server
|
||||
and returns a synchronous Observable whose value is available immediately.
|
||||
and returns a synchronous observable whose value is available immediately.
|
||||
|
||||
You can write many useful tests with this spy, even though its `Observable` is synchronous.
|
||||
|
||||
|
@ -1114,14 +1113,14 @@ Or you can copy this one from the sample code.
|
|||
|
||||
This helper's observable emits the `data` value in the next turn of the JavaScript engine.
|
||||
|
||||
[RxJS `defer()`](http://reactivex.io/documentation/operators/defer.html) returns an observable.
|
||||
The [RxJS `defer()` operator](http://reactivex.io/documentation/operators/defer.html) returns an observable.
|
||||
It takes a factory function that returns either a promise or an observable.
|
||||
When something subscribes to _defer_'s observable,
|
||||
it adds the subscriber to a new observable created with that factory.
|
||||
|
||||
RxJS `defer()` transform the `Promise.resolve()` into a new observable that,
|
||||
The `defer()` operator transforms the `Promise.resolve()` into a new observable that,
|
||||
like `HttpClient`, emits once and completes.
|
||||
Subscribers will be unsubscribed after they receive the data value.
|
||||
Subscribers are unsubscribed after they receive the data value.
|
||||
|
||||
There's a similar helper for producing an async error.
|
||||
|
||||
|
@ -1689,9 +1688,8 @@ Here's the `HeroDetailComponent` constructor:
|
|||
|
||||
The `HeroDetail` component needs the `id` parameter so it can fetch
|
||||
the corresponding hero via the `HeroDetailService`.
|
||||
|
||||
The component has to get the `id` from the `ActivatedRoute.paramMap` property
|
||||
which is an _Observable_.
|
||||
which is an `Observable`.
|
||||
|
||||
It can't just reference the `id` property of the `ActivatedRoute.paramMap`.
|
||||
The component has to _subscribe_ to the `ActivatedRoute.paramMap` observable and be prepared
|
||||
|
|
|
@ -1342,7 +1342,7 @@ and the other loads the details of a specified phone:
|
|||
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="fullclass" title="app/core/phone/phone.service.ts">
|
||||
</code-example>
|
||||
|
||||
The methods now return Observables of type `PhoneData` and `PhoneData[]`. This is
|
||||
The methods now return observables of type `PhoneData` and `PhoneData[]`. This is
|
||||
a type you don't have yet. Add a simple interface for it:
|
||||
|
||||
<code-example path="upgrade-phonecat-2-hybrid/app/core/phone/phone.service.ts" region="phonedata-interface" title="app/core/phone/phone.service.ts (interface)" linenums="false">
|
||||
|
@ -1385,14 +1385,14 @@ it's really an instance of the `Phone` class and you annotate its type according
|
|||
|
||||
Now there are two AngularJS components using an Angular service!
|
||||
The components don't need to be aware of this, though the fact that the
|
||||
service returns Observables and not Promises is a bit of a giveaway.
|
||||
service returns observables and not promises is a bit of a giveaway.
|
||||
In any case, what you've achieved is a migration of a service to Angular
|
||||
without having to yet migrate the components that use it.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
You could use the `toPromise` method of `Observable` to turn those
|
||||
Observables into Promises in the service. In many cases that reduce
|
||||
observables into promises in the service. In many cases that reduce
|
||||
the number of changes to the component controllers.
|
||||
|
||||
</div>
|
||||
|
|
|
@ -446,7 +446,7 @@ Here are the code files discussed on this page and your app should look like thi
|
|||
* You used [Angular Dependency Injection](guide/dependency-injection) to inject it into a component.
|
||||
* You gave the `HeroService` _get data_ method an asynchronous signature.
|
||||
* You discovered `Observable` and the RxJS _Observable_ library.
|
||||
* You used RxJS `of()` to return an _Observable_ of mock heroes (`Observable<Hero[]>`).
|
||||
* You used RxJS `of()` to return an observable of mock heroes (`Observable<Hero[]>`).
|
||||
* The component's `ngOnInit` lifecycle hook calls the `HeroService` method, not the constructor.
|
||||
* You created a `MessageService` for loosely-coupled communication between classes.
|
||||
* The `HeroService` injected into a component is created with another injected service,
|
||||
|
|
|
@ -145,8 +145,8 @@ All `HttpClient` methods return an RxJS `Observable` of something.
|
|||
HTTP is a request/response protocol.
|
||||
You make a request, it returns a single response.
|
||||
|
||||
In general, an `Observable` _can_ return multiple values over time.
|
||||
An `Observable` from `HttpClient` always emits a single value and then completes, never to emit again.
|
||||
In general, an observable _can_ return multiple values over time.
|
||||
An observable from `HttpClient` always emits a single value and then completes, never to emit again.
|
||||
|
||||
This particular `HttpClient.get` call returns an `Observable<Hero[]>`, literally "_an observable of hero arrays_". In practice, it will only return a single hero array.
|
||||
|
||||
|
@ -513,8 +513,8 @@ The `searchTerms` becomes an `Observable` emitting a steady stream of search ter
|
|||
Passing a new search term directly to the `searchHeroes()` after every user keystroke would create an excessive amount of HTTP requests,
|
||||
taxing server resources and burning through the cellular network data plan.
|
||||
|
||||
Instead, the `ngOnInit()` method pipes the `searchTerms` _observable_ through a sequence of RxJS operators that reduce the number of calls to the `searchHeroes()`,
|
||||
ultimately returning an _observable_ of timely hero search results (each a `Hero[]`).
|
||||
Instead, the `ngOnInit()` method pipes the `searchTerms` observable through a sequence of RxJS operators that reduce the number of calls to the `searchHeroes()`,
|
||||
ultimately returning an observable of timely hero search results (each a `Hero[]`).
|
||||
|
||||
Here's the code.
|
||||
|
||||
|
@ -529,7 +529,7 @@ Here's the code.
|
|||
before passing along the latest string. You'll never make requests more frequently than 300ms.
|
||||
|
||||
|
||||
* `distinctUntilChanged` ensures that a request is sent only if the filter text changed.
|
||||
* `distinctUntilChanged()` ensures that a request is sent only if the filter text changed.
|
||||
|
||||
|
||||
* `switchMap()` calls the search service for each search term that makes it through `debounce` and `distinctUntilChanged`.
|
||||
|
@ -648,7 +648,7 @@ You're at the end of your journey, and you've accomplished a lot.
|
|||
* You extended `HeroService` to support `post()`, `put()`, and `delete()` methods.
|
||||
* You updated the components to allow adding, editing, and deleting of heroes.
|
||||
* You configured an in-memory web API.
|
||||
* You learned how to use Observables.
|
||||
* You learned how to use observables.
|
||||
|
||||
This concludes the "Tour of Heroes" tutorial.
|
||||
You're ready to learn more about Angular development in the fundamentals section,
|
||||
|
|
Loading…
Reference in New Issue