Skip to content

Commit 131b093

Browse files
committed
feat(facade/async): create EventEmitter
1 parent d452155 commit 131b093

File tree

3 files changed

+124
-0
lines changed

3 files changed

+124
-0
lines changed

core.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export { Pipe, PipeTransform } from './src/core/pipes';
1616
export * from './src/core/linker';
1717
export * from './src/core/change_detection';
1818
export { enableProdMode } from './src/facade/lang';
19+
export { EventEmitter } from './src/facade/facade';

src/facade/async.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import { noop } from './lang';
2+
import { isFunction } from './lang';
3+
/**
4+
* Use by directives and components to emit custom Events.
5+
*
6+
* ### Examples
7+
*
8+
* In the following example, `Zippy` alternatively emits `open` and `close` events when its
9+
* title gets clicked:
10+
*
11+
* ```
12+
* @Component({
13+
* selector: 'zippy',
14+
* template: `
15+
* <div class="zippy">
16+
* <div (click)="toggle()">Toggle</div>
17+
* <div [hidden]="!visible">
18+
* <ng-content></ng-content>
19+
* </div>
20+
* </div>`})
21+
* export class Zippy {
22+
* visible: boolean = true;
23+
* @Output() open: EventEmitter<any> = new EventEmitter();
24+
* @Output() close: EventEmitter<any> = new EventEmitter();
25+
*
26+
* toggle() {
27+
* this.visible = !this.visible;
28+
* if (this.visible) {
29+
* this.open.emit(null);
30+
* } else {
31+
* this.close.emit(null);
32+
* }
33+
* }
34+
* }
35+
* ```
36+
*
37+
* Use Rx.Observable but provides an adapter to make it work as specified here:
38+
* https://github.com/jhusain/observable-spec
39+
*
40+
* Once a reference implementation of the spec is available, switch to it.
41+
*/
42+
export class EventEmitter<T> {
43+
/** @internal */
44+
_isAsync: boolean;
45+
46+
private _generatorOrNextFn: Function[] = [];
47+
private _ngExpressionBindingCb: Function = noop;
48+
49+
/** @internal */
50+
static makeNgExpBindingEmittable( cb: Function ) {
51+
(cb as any)._generatorOrNextFn = [];
52+
53+
(cb as any).emit = function ( value: any ) {
54+
EventEmitter.createEmit( value, cb, cb );
55+
};
56+
57+
(cb as any)._dispose = function ( cbRef ) {
58+
EventEmitter.createDisposable( cbRef, cb )
59+
};
60+
61+
(cb as any).subscribe = function ( generatorOrNext?: Function ): Function {
62+
return EventEmitter.createSubscribe( generatorOrNext, cb );
63+
};
64+
}
65+
66+
/** @internal */
67+
private static createDisposable( cbRef, _context: any ) {
68+
const refIdx = _context._generatorOrNextFn.indexOf( cbRef );
69+
if ( refIdx === -1 ) {
70+
return;
71+
}
72+
_context._generatorOrNextFn.splice( refIdx, 1 );
73+
}
74+
75+
/** @internal */
76+
private static createEmit( value, _context: any, exprBindingCb?: Function ) {
77+
const payload = { $event: value };
78+
79+
if ( isFunction( exprBindingCb ) ) {
80+
exprBindingCb( payload );
81+
} else {
82+
_context._ngExpressionBindingCb( payload );
83+
}
84+
85+
// notify all subscribers
86+
_context._generatorOrNextFn.forEach( observerFn => observerFn( value ) );
87+
}
88+
89+
/** @internal */
90+
private static createSubscribe( generatorOrNext, _context: any ): Function {
91+
console.warn( 'NOTE: This is not a real Observable!' );
92+
_context._generatorOrNextFn.push( generatorOrNext );
93+
94+
return () => _context._dispose( generatorOrNext );
95+
}
96+
97+
98+
/**
99+
* Creates an instance of [EventEmitter], which depending on [isAsync],
100+
* delivers events synchronously or asynchronously.
101+
*/
102+
constructor( isAsync: boolean = true ) {
103+
this._isAsync = isAsync;
104+
}
105+
106+
private _dispose( cbRef ) {
107+
EventEmitter.createDisposable( cbRef, this );
108+
}
109+
110+
/** @internal */
111+
wrapNgExpBindingToEmitter( cb: Function ) {
112+
this._ngExpressionBindingCb = cb;
113+
}
114+
115+
emit( value: T ) {
116+
EventEmitter.createEmit( value, this );
117+
}
118+
119+
subscribe( generatorOrNext?: Function, error?: any, complete?: any ): Function {
120+
return EventEmitter.createSubscribe( generatorOrNext, this );
121+
}
122+
}

src/facade/facade.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
// None :)
33

44
export {Type} from './lang';
5+
export {EventEmitter} from './async';

0 commit comments

Comments
 (0)