Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

docs(pipes): improve FetchJsonPipe discussion #2923

Merged
merged 1 commit into from
Dec 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions public/docs/_examples/pipes/ts/app/fetch-json.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// #docregion
import { Pipe, PipeTransform } from '@angular/core';
import { Http } from '@angular/http';
import './rxjs-extensions';

// #docregion pipe-metadata
@Pipe({
Expand All @@ -9,20 +10,20 @@ import { Http } from '@angular/http';
})
// #enddocregion pipe-metadata
export class FetchJsonPipe implements PipeTransform {
private fetchedJson: any = null;
private prevUrl = '';
private cachedData: any = null;
private cachedUrl = '';

constructor(private _http: Http) { }
constructor(private http: Http) { }

transform(url: string): any {
if (url !== this.prevUrl) {
this.prevUrl = url;
this.fetchedJson = null;
this._http.get(url)
if (url !== this.cachedUrl) {
this.cachedData = null;
this.cachedUrl = url;
this.http.get(url)
.map( result => result.json() )
.subscribe( result => this.fetchedJson = result );
.subscribe( result => this.cachedData = result );
}

return this.fetchedJson;
return this.cachedData;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// #docregion
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
import './rxjs-extensions';

@Component({
selector: 'hero-message',
Expand Down
7 changes: 2 additions & 5 deletions public/docs/_examples/pipes/ts/app/hero-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Component } from '@angular/core';

@Component({
selector: 'hero-list',
// #docregion template
template: `
<h2>Heroes from JSON File</h2>

Expand All @@ -12,9 +11,7 @@ import { Component } from '@angular/core';
</div>

<p>Heroes as JSON:
{{'heroes.json' | fetch | json}}
</p>
`
// #enddocregion template
{{'heroes.json' | fetch | json}}
</p>`
})
export class HeroListComponent { }
1 change: 0 additions & 1 deletion public/docs/_examples/pipes/ts/app/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import 'rxjs/Rx';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
5 changes: 5 additions & 0 deletions public/docs/_examples/pipes/ts/app/rxjs-extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Extensions to RxJS used in this app.
import 'rxjs/add/observable/interval';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
47 changes: 20 additions & 27 deletions public/docs/ts/_cache/guide/pipes.jade
Original file line number Diff line number Diff line change
Expand Up @@ -361,57 +361,50 @@ h3#async-pipe The impure #[i AsyncPipe]
The component doesn't have to subscribe to the async data source,
it doesn't extract the resolved values and expose them for binding,
and the component doesn't have to unsubscribe when it is destroyed
(a potent source of memory leaks).
(a potential source of memory leaks).

### An impure caching pipe

Let's write one more impure pipe, a pipe that makes an HTTP request to the server.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
If we're not careful, this pipe will punish the server with requests.
Let's write one more impure pipe, a pipe that makes an HTTP request.

We are careful. Our pipe only makes a server call if the request URL has changed.
It caches the request URL and waits for a result which it also caches when it arrives.
The pipe returns the cached result (which is null while a request is in flight)
after every Angular call and only contacts the server as necessary.
Remember that impure pipes are called every few milliseconds.
If we're not careful, this pipe will punish the server with requests.

Here's the code, which uses the [Angular http](server-communication.html) facility
to retrieve a `heroes.json` file:
We are careful.
The pipe only calls the server when the request URL changes and it caches the server response.
Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:

+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked
Then we demonstrate it in a harness component whose template defines two bindings to this pipe.
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)')
:marked
Despite the two bindings and what we know to be frequent pipe calls,
the nework tab in the browser developer tools confirms that there is only one request for the file.
Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
both requesting the heroes from the `heroes.json` file.

+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this:

figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")

:marked
A breakpoint on the pipe's request for data shows that
* each binding gets its own pipe instance
* each pipe instance caches its own url and data
* each pipe instance only calls the server once

:marked
### *JsonPipe*

The second binding involving the `FetchPipe` uses more pipe chaining.
We take the same fetched results displayed in the first binding
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
The second `fetch` pipe binding above demonstrates more pipe chaining.
It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.

.callout.is-helpful
header Debugging with the json pipe
:marked
The [JsonPipe](../api/common/index/JsonPipe-pipe.html)
provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding.

:marked
Here's the complete component implementation:

+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')


a(id="pure-pipe-pure-fn")
:marked
### Pure pipes and pure functions
Expand Down
43 changes: 18 additions & 25 deletions public/docs/ts/latest/guide/pipes.jade
Original file line number Diff line number Diff line change
Expand Up @@ -365,40 +365,38 @@ h3#async-pipe The impure #[i AsyncPipe]

### An impure caching pipe

Let's write one more impure pipe, a pipe that makes an HTTP request to the server.
Normally, that's a horrible idea.
It's probably a horrible idea no matter what we do.
We're forging ahead anyway to make a point.
Remember that impure pipes are called every few microseconds.
If we're not careful, this pipe will punish the server with requests.
Let's write one more impure pipe, a pipe that makes an HTTP request.

We are careful. Our pipe only makes a server call if the request URL has changed.
It caches the request URL and waits for a result which it also caches when it arrives.
The pipe returns the cached result (which is null while a request is in flight)
after every Angular call and only contacts the server as necessary.
Remember that impure pipes are called every few milliseconds.
If we're not careful, this pipe will punish the server with requests.

Here's the code, which uses the [Angular http](server-communication.html) facility
to retrieve a `heroes.json` file:
We are careful.
The pipe only calls the server when the request URL changes and it caches the server response.
Here's the code, which uses the [Angular http](server-communication.html) client to retrieve data:

+makeExample('pipes/ts/app/fetch-json.pipe.ts', null, 'app/fetch-json.pipe.ts')
:marked
Then we demonstrate it in a harness component whose template defines two bindings to this pipe.
+makeExample('pipes/ts/app/hero-list.component.ts', 'template', 'app/hero-list.component.ts (template)')
:marked
Despite the two bindings and what we know to be frequent pipe calls,
the nework tab in the browser developer tools confirms that there is only one request for the file.
Then we demonstrate it in a harness component whose template defines two bindings to this pipe,
both requesting the heroes from the `heroes.json` file.

+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')
:marked
The component renders like this:

figure.image-display
img(src='/resources/images/devguide/pipes/hero-list.png' alt="Hero List")

:marked
A breakpoint on the pipe's request for data shows that
* each binding gets its own pipe instance
* each pipe instance caches its own url and data
* each pipe instance only calls the server once

:marked
### *JsonPipe*

The second binding involving the `FetchPipe` uses more pipe chaining.
We take the same fetched results displayed in the first binding
and display them again, this time in JSON format by chaining through to the built-in `JsonPipe`.
The second `fetch` pipe binding above demonstrates more pipe chaining.
It displays the same hero data in JSON format by chaining through to the built-in `JsonPipe`.

.callout.is-helpful
header Debugging with the json pipe
Expand All @@ -407,11 +405,6 @@ figure.image-display
provides an easy way to diagnosis a mysteriously failing data binding or
inspect an object for future binding.

:marked
Here's the complete component implementation:

+makeExample('pipes/ts/app/hero-list.component.ts', null, 'app/hero-list.component.ts')

a(id="pure-pipe-pure-fn")
:marked
### Pure pipes and pure functions
Expand Down