Pipe (back-ported from Angular 2)
AsyncPipe
The async
pipe subscribes to an Observable
or Promise
and returns the latest value it has emitted.
When a new value is emitted, the async
pipe marks the component to be checked for changes. (Runs $scope.$digest())
When the component gets destroyed, the async
pipe unsubscribes automatically to avoid potential memory leaks.
Registration
- you have to register it via the
declarations
array on an@NgModule
.
// app.module.ts
import { NgModule } from 'ng-metadata/core';
import { AsyncPipe } from 'ng-metadata/common';
@NgModule({
declarations: [ AsyncPipe ]
})
export class AppModule {}
Usage
object | async // for non observable object | async:this // for observable
where:
object
is one of typeObservable
,Promise
, 'ng.IPromise' or 'ng.IHttpPromise'this
is pipe parameter (in angular 1 reference to local $Scope ( we need for Observable disposal)
If you are using async with observables nad you don't provide scope we will throw Error to let you know that you forgot this
, #perfmatters baby!
Example
import { Observable } from 'rxjs/Observable'
import { Subscriber } from 'rxjs/Subscriber'
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/scan';
import { Component, Inject } from 'ng-metadata/core';
// It's also possible to use 'async' with Observables. The example below binds the 'time' Observable to the view.
// Every 500ms, the 'time' Observable updates the view with the current time.
@Component({
selector: 'async-task',
template: `
Clock: {{ $ctrl.clock$ | async:this | date:'M/d/yy h:mm:ss a' }} <br>
Timer: {{ $ctrl.timer$ | async:this }} <br>
Async Stream via scan:
<ul><li ng-repeat="u in $ctrl.stream$ | async:this">{{ u }}</li></ul>
`
})
class AsyncTaskComponent {
clock$ = Observable.create((observer: Subscriber<number>) => {
this.$interval(() => observer.next(new Date().getTime()), 500);
});
timer$ = Observable.interval(1000).take(50);
stream$ = Observable.interval(1500).take(10).scan((acc, item) => [...acc, item], []);
constructor(@Inject('$interval') private $interval: ng.IIntervalService){}
}
@Component({
selector: 'async-example',
template: `
<button ng-click="$ctrl.renderTimers=!$ctrl.renderTimers">Show Timers</button>
<async-task ng-if="$ctrl.renderTimers"></async-task>
<br>
<div>
<p>Wait for it... {{ $ctrl.greeting | async }}</p>
<button ng-click="$ctrl.clicked()">{{ $ctrl.arrived ? 'Reset' : 'Resolve' }}</button>
</div>
<div>
<h4>Rx repos:</h4>
<blockquote ng-hide="$ctrl.repos | async">Loading...</blockquote>
<ul>
<li ng-repeat="repo in $ctrl.repos | async">
<a href="{{ repo.html_url }}" target="_blank">
{{ repo.name }}
</a>
</li>
</ul>
<pre style="overflow:auto;max-height:250px;">{{ $ctrl.repos | async | json }}</pre>
</div>
`
})
export class AsyncExampleComponent {
greeting: ng.IPromise<string> = null;
arrived: boolean = false;
repos = this.$http.get('https://api.github.com/orgs/Reactive-Extensions/repos');
private resolve: Function = null;
constructor(
@Inject('$q') private $q:ng.IQService,
@Inject('$http') private $http:ng.IHttpService
) {
this.reset();
}
reset() {
this.arrived = false;
this.greeting = this.$q((resolve, reject) => { this.resolve = resolve; });
}
clicked() {
if (this.arrived) {
this.reset();
} else {
this.resolve('hi there!');
this.arrived = true;
}
}
}