feat(refactor): replaced ObservablePipe and PromisePipe with AsyncPipe
This commit is contained in:
@ -7,8 +7,7 @@ import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs
|
||||
import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
|
||||
import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
|
||||
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
|
||||
import {ObservablePipeFactory} from './pipes/observable_pipe';
|
||||
import {PromisePipeFactory} from './pipes/promise_pipe';
|
||||
import {AsyncPipeFactory} from './pipes/async_pipe';
|
||||
import {UpperCasePipe} from './pipes/uppercase_pipe';
|
||||
import {LowerCasePipe} from './pipes/lowercase_pipe';
|
||||
import {JsonPipe} from './pipes/json_pipe';
|
||||
@ -75,11 +74,8 @@ export const iterableDiff: IterableDifferFactory[] =
|
||||
/**
|
||||
* Async binding to such types as Observable.
|
||||
*/
|
||||
export const async: List<PipeFactory> = CONST_EXPR([
|
||||
CONST_EXPR(new ObservablePipeFactory()),
|
||||
CONST_EXPR(new PromisePipeFactory()),
|
||||
CONST_EXPR(new NullPipeFactory())
|
||||
]);
|
||||
export const async: List<PipeFactory> =
|
||||
CONST_EXPR([CONST_EXPR(new AsyncPipeFactory()), CONST_EXPR(new NullPipeFactory())]);
|
||||
|
||||
/**
|
||||
* Uppercase text transform.
|
||||
|
134
modules/angular2/src/change_detection/pipes/async_pipe.ts
Normal file
134
modules/angular2/src/change_detection/pipes/async_pipe.ts
Normal file
@ -0,0 +1,134 @@
|
||||
import {isBlank, isPresent, isPromise, CONST, BaseException} from 'angular2/src/facade/lang';
|
||||
import {Observable, Promise, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {Pipe, WrappedValue, PipeFactory} from './pipe';
|
||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
|
||||
|
||||
class ObservableStrategy {
|
||||
createSubscription(async: any, updateLatestValue: any): any {
|
||||
return ObservableWrapper.subscribe(async, updateLatestValue, e => { throw e; });
|
||||
}
|
||||
|
||||
dispose(subscription: any): void { ObservableWrapper.dispose(subscription); }
|
||||
|
||||
onDestroy(subscription: any): void { ObservableWrapper.dispose(subscription); }
|
||||
}
|
||||
|
||||
class PromiseStrategy {
|
||||
createSubscription(async: any, updateLatestValue: any): any {
|
||||
return async.then(updateLatestValue);
|
||||
}
|
||||
|
||||
dispose(subscription: any): void {}
|
||||
|
||||
onDestroy(subscription: any): void {}
|
||||
}
|
||||
|
||||
var _promiseStrategy = new PromiseStrategy();
|
||||
var _observableStrategy = new ObservableStrategy();
|
||||
|
||||
|
||||
/**
|
||||
* Implements async bindings to Observable and Promise.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* In this example we bind the description observable to the DOM. The async pipe will convert an
|
||||
*observable to the
|
||||
* latest value it emitted. It will also request a change detection check when a new value is
|
||||
*emitted.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "task-cmp",
|
||||
* changeDetection: ON_PUSH
|
||||
* })
|
||||
* @View({
|
||||
* template: "Task Description {{ description | async }}"
|
||||
* })
|
||||
* class Task {
|
||||
* description:Observable<string>;
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
export class AsyncPipe implements Pipe {
|
||||
_latestValue: Object = null;
|
||||
_latestReturnedValue: Object = null;
|
||||
|
||||
_subscription: Object = null;
|
||||
_obj: Observable | Promise<any> = null;
|
||||
private _strategy: any = null;
|
||||
|
||||
constructor(public _ref: ChangeDetectorRef) {}
|
||||
|
||||
supports(obj: any): boolean { return true; }
|
||||
|
||||
onDestroy(): void {
|
||||
if (isPresent(this._subscription)) {
|
||||
this._dispose();
|
||||
}
|
||||
}
|
||||
|
||||
transform(obj: Observable | Promise<any>, args?: any[]): any {
|
||||
if (isBlank(this._obj)) {
|
||||
if (isPresent(obj)) {
|
||||
this._subscribe(obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obj !== this._obj) {
|
||||
this._dispose();
|
||||
return this.transform(obj);
|
||||
}
|
||||
|
||||
if (this._latestValue === this._latestReturnedValue) {
|
||||
return this._latestReturnedValue;
|
||||
} else {
|
||||
this._latestReturnedValue = this._latestValue;
|
||||
return WrappedValue.wrap(this._latestValue);
|
||||
}
|
||||
}
|
||||
|
||||
_subscribe(obj: Observable | Promise<any>): void {
|
||||
this._obj = obj;
|
||||
this._strategy = this._selectStrategy(obj);
|
||||
this._subscription =
|
||||
this._strategy.createSubscription(obj, value => this._updateLatestValue(obj, value));
|
||||
}
|
||||
|
||||
_selectStrategy(obj: Observable | Promise<any>) {
|
||||
if (isPromise(obj)) {
|
||||
return _promiseStrategy;
|
||||
} else if (ObservableWrapper.isObservable(obj)) {
|
||||
return _observableStrategy;
|
||||
} else {
|
||||
throw new BaseException(`Async pipe does not support object '${obj}'`);
|
||||
}
|
||||
}
|
||||
|
||||
_dispose(): void {
|
||||
this._strategy.dispose(this._subscription);
|
||||
this._latestValue = null;
|
||||
this._latestReturnedValue = null;
|
||||
this._subscription = null;
|
||||
this._obj = null;
|
||||
}
|
||||
|
||||
_updateLatestValue(async: any, value: Object) {
|
||||
if (async === this._obj) {
|
||||
this._latestValue = value;
|
||||
this._ref.requestCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a factory for [AsyncPipe].
|
||||
*/
|
||||
@CONST()
|
||||
export class AsyncPipeFactory implements PipeFactory {
|
||||
supports(obj: any): boolean { return true; }
|
||||
create(cdRef: ChangeDetectorRef): Pipe { return new AsyncPipe(cdRef); }
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
import {Observable, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang';
|
||||
import {Pipe, WrappedValue, PipeFactory} from './pipe';
|
||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
|
||||
/**
|
||||
* Implements async bindings to Observable.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* In this example we bind the description observable to the DOM. The async pipe will convert an
|
||||
*observable to the
|
||||
* latest value it emitted. It will also request a change detection check when a new value is
|
||||
*emitted.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "task-cmp",
|
||||
* changeDetection: ON_PUSH
|
||||
* })
|
||||
* @View({
|
||||
* template: "Task Description {{ description | async }}"
|
||||
* })
|
||||
* class Task {
|
||||
* description:Observable<string>;
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
export class ObservablePipe implements Pipe {
|
||||
_latestValue: Object = null;
|
||||
_latestReturnedValue: Object = null;
|
||||
|
||||
_subscription: Object = null;
|
||||
_observable: Observable = null;
|
||||
|
||||
constructor(public _ref: ChangeDetectorRef) {}
|
||||
|
||||
supports(obs: any): boolean { return ObservableWrapper.isObservable(obs); }
|
||||
|
||||
onDestroy(): void {
|
||||
if (isPresent(this._subscription)) {
|
||||
this._dispose();
|
||||
}
|
||||
}
|
||||
|
||||
transform(obs: Observable, args: List<any> = null): any {
|
||||
if (isBlank(this._subscription)) {
|
||||
this._subscribe(obs);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (obs !== this._observable) {
|
||||
this._dispose();
|
||||
return this.transform(obs);
|
||||
}
|
||||
|
||||
if (this._latestValue === this._latestReturnedValue) {
|
||||
return this._latestReturnedValue;
|
||||
} else {
|
||||
this._latestReturnedValue = this._latestValue;
|
||||
return WrappedValue.wrap(this._latestValue);
|
||||
}
|
||||
}
|
||||
|
||||
_subscribe(obs: Observable): void {
|
||||
this._observable = obs;
|
||||
this._subscription = ObservableWrapper.subscribe(obs, value => this._updateLatestValue(value),
|
||||
e => { throw e; });
|
||||
}
|
||||
|
||||
_dispose(): void {
|
||||
ObservableWrapper.dispose(this._subscription);
|
||||
this._latestValue = null;
|
||||
this._latestReturnedValue = null;
|
||||
this._subscription = null;
|
||||
this._observable = null;
|
||||
}
|
||||
|
||||
_updateLatestValue(value: Object) {
|
||||
this._latestValue = value;
|
||||
this._ref.requestCheck();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a factory for [ObervablePipe].
|
||||
*/
|
||||
@CONST()
|
||||
export class ObservablePipeFactory implements PipeFactory {
|
||||
supports(obs: any): boolean { return ObservableWrapper.isObservable(obs); }
|
||||
|
||||
create(cdRef: ChangeDetectorRef): Pipe { return new ObservablePipe(cdRef); }
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {isBlank, isPresent, isPromise, CONST} from 'angular2/src/facade/lang';
|
||||
import {Pipe, PipeFactory, WrappedValue} from './pipe';
|
||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
|
||||
/**
|
||||
* Implements async bindings to Promise.
|
||||
*
|
||||
* # Example
|
||||
*
|
||||
* In this example we bind the description promise to the DOM.
|
||||
* The async pipe will convert a promise to the value with which it is resolved. It will also
|
||||
* request a change detection check when the promise is resolved.
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: "task-cmp",
|
||||
* changeDetection: ON_PUSH
|
||||
* })
|
||||
* @View({
|
||||
* template: "Task Description {{ description | async }}"
|
||||
* })
|
||||
* class Task {
|
||||
* description:Promise<string>;
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
export class PromisePipe implements Pipe {
|
||||
_latestValue: Object = null;
|
||||
_latestReturnedValue: Object = null;
|
||||
_sourcePromise: Promise<any>;
|
||||
|
||||
constructor(public _ref: ChangeDetectorRef) {}
|
||||
|
||||
supports(promise: any): boolean { return isPromise(promise); }
|
||||
|
||||
onDestroy(): void {
|
||||
if (isPresent(this._sourcePromise)) {
|
||||
this._latestValue = null;
|
||||
this._latestReturnedValue = null;
|
||||
this._sourcePromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
transform(promise: Promise<any>, args: List<any> = null): any {
|
||||
if (isBlank(this._sourcePromise)) {
|
||||
this._sourcePromise = promise;
|
||||
promise.then((val) => {
|
||||
if (this._sourcePromise === promise) {
|
||||
this._updateLatestValue(val);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (promise !== this._sourcePromise) {
|
||||
this._sourcePromise = null;
|
||||
return this.transform(promise);
|
||||
}
|
||||
|
||||
if (this._latestValue === this._latestReturnedValue) {
|
||||
return this._latestReturnedValue;
|
||||
} else {
|
||||
this._latestReturnedValue = this._latestValue;
|
||||
return WrappedValue.wrap(this._latestValue);
|
||||
}
|
||||
}
|
||||
|
||||
_updateLatestValue(value: Object) {
|
||||
this._latestValue = value;
|
||||
this._ref.requestCheck();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a factory for [PromisePipe].
|
||||
*/
|
||||
@CONST()
|
||||
export class PromisePipeFactory implements PipeFactory {
|
||||
supports(promise: any): boolean { return isPromise(promise); }
|
||||
|
||||
create(cdRef: ChangeDetectorRef): Pipe { return new PromisePipe(cdRef); }
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
ChangeDetector,
|
||||
ChangeDetectorRef,
|
||||
ProtoChangeDetector,
|
||||
DynamicChangeDetector
|
||||
} from 'angular2/src/change_detection/change_detection';
|
||||
@ -26,3 +27,7 @@ export class SpyPipeFactory extends SpyObject {}
|
||||
export class SpyDependencyProvider extends SpyObject {}
|
||||
|
||||
export class SpyIterableDifferFactory extends SpyObject {}
|
||||
|
||||
export class SpyChangeDetectorRef extends SpyObject {
|
||||
constructor() { super(ChangeDetectorRef); }
|
||||
}
|
||||
|
Reference in New Issue
Block a user