refactor: remove EventEmitter from facade (#14837)
As of right now each module has its own copy of the EventEmitter contributing to bloat.
This commit is contained in:
committed by
Chuck Jazdzewski
parent
728fe472f8
commit
928c5657c8
@@ -1,116 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
|
||||
export {Observable} from 'rxjs/Observable';
|
||||
export {Subject} from 'rxjs/Subject';
|
||||
|
||||
/**
|
||||
* Use by directives and components to emit custom Events.
|
||||
*
|
||||
* ### Examples
|
||||
*
|
||||
* In the following example, `Zippy` alternatively emits `open` and `close` events when its
|
||||
* title gets clicked:
|
||||
*
|
||||
* ```
|
||||
* @Component({
|
||||
* selector: 'zippy',
|
||||
* template: `
|
||||
* <div class="zippy">
|
||||
* <div (click)="toggle()">Toggle</div>
|
||||
* <div [hidden]="!visible">
|
||||
* <ng-content></ng-content>
|
||||
* </div>
|
||||
* </div>`})
|
||||
* export class Zippy {
|
||||
* visible: boolean = true;
|
||||
* @Output() open: EventEmitter<any> = new EventEmitter();
|
||||
* @Output() close: EventEmitter<any> = new EventEmitter();
|
||||
*
|
||||
* toggle() {
|
||||
* this.visible = !this.visible;
|
||||
* if (this.visible) {
|
||||
* this.open.emit(null);
|
||||
* } else {
|
||||
* this.close.emit(null);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The events payload can be accessed by the parameter `$event` on the components output event
|
||||
* handler:
|
||||
*
|
||||
* ```
|
||||
* <zippy (open)="onOpen($event)" (close)="onClose($event)"></zippy>
|
||||
* ```
|
||||
*
|
||||
* Uses Rx.Observable but provides an adapter to make it work as specified here:
|
||||
* https://github.com/jhusain/observable-spec
|
||||
*
|
||||
* Once a reference implementation of the spec is available, switch to it.
|
||||
* @stable
|
||||
*/
|
||||
export class EventEmitter<T> extends Subject<T> {
|
||||
// TODO: mark this as internal once all the facades are gone
|
||||
// we can't mark it as internal now because EventEmitter exported via @angular/core would not
|
||||
// contain this property making it incompatible with all the code that uses EventEmitter via
|
||||
// facades, which are local to the code and do not have this property stripped.
|
||||
// tslint:disable-next-line
|
||||
__isAsync: boolean;
|
||||
|
||||
/**
|
||||
* Creates an instance of [EventEmitter], which depending on [isAsync],
|
||||
* delivers events synchronously or asynchronously.
|
||||
*/
|
||||
constructor(isAsync: boolean = false) {
|
||||
super();
|
||||
this.__isAsync = isAsync;
|
||||
}
|
||||
|
||||
emit(value?: T) { super.next(value); }
|
||||
|
||||
subscribe(generatorOrNext?: any, error?: any, complete?: any): any {
|
||||
let schedulerFn: (t: any) => any;
|
||||
let errorFn = (err: any): any => null;
|
||||
let completeFn = (): any => null;
|
||||
|
||||
if (generatorOrNext && typeof generatorOrNext === 'object') {
|
||||
schedulerFn = this.__isAsync ? (value: any) => {
|
||||
setTimeout(() => generatorOrNext.next(value));
|
||||
} : (value: any) => { generatorOrNext.next(value); };
|
||||
|
||||
if (generatorOrNext.error) {
|
||||
errorFn = this.__isAsync ? (err) => { setTimeout(() => generatorOrNext.error(err)); } :
|
||||
(err) => { generatorOrNext.error(err); };
|
||||
}
|
||||
|
||||
if (generatorOrNext.complete) {
|
||||
completeFn = this.__isAsync ? () => { setTimeout(() => generatorOrNext.complete()); } :
|
||||
() => { generatorOrNext.complete(); };
|
||||
}
|
||||
} else {
|
||||
schedulerFn = this.__isAsync ? (value: any) => { setTimeout(() => generatorOrNext(value)); } :
|
||||
(value: any) => { generatorOrNext(value); };
|
||||
|
||||
if (error) {
|
||||
errorFn =
|
||||
this.__isAsync ? (err) => { setTimeout(() => error(err)); } : (err) => { error(err); };
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
completeFn =
|
||||
this.__isAsync ? () => { setTimeout(() => complete()); } : () => { complete(); };
|
||||
}
|
||||
}
|
||||
|
||||
return super.subscribe(schedulerFn, errorFn, completeFn);
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@angular/core/testing/testing_internal';
|
||||
import {EventEmitter} from '../src/async';
|
||||
|
||||
export function main() {
|
||||
describe('EventEmitter', () => {
|
||||
let emitter: EventEmitter<any>;
|
||||
|
||||
beforeEach(() => { emitter = new EventEmitter(); });
|
||||
|
||||
it('should call the next callback',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
emitter.subscribe({
|
||||
next: (value: any) => {
|
||||
expect(value).toEqual(99);
|
||||
async.done();
|
||||
}
|
||||
});
|
||||
emitter.emit(99);
|
||||
}));
|
||||
|
||||
it('should call the throw callback',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
emitter.subscribe({
|
||||
next: () => {},
|
||||
error: (error: any) => {
|
||||
expect(error).toEqual('Boom');
|
||||
async.done();
|
||||
}
|
||||
});
|
||||
emitter.error('Boom');
|
||||
}));
|
||||
|
||||
it('should work when no throw callback is provided',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
emitter.subscribe({next: () => {}, error: (_: any) => { async.done(); }});
|
||||
emitter.error('Boom');
|
||||
}));
|
||||
|
||||
it('should call the return callback',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
emitter.subscribe(
|
||||
{next: () => {}, error: (_: any) => {}, complete: () => { async.done(); }});
|
||||
emitter.complete();
|
||||
}));
|
||||
|
||||
it('should subscribe to the wrapper synchronously', () => {
|
||||
let called = false;
|
||||
emitter.subscribe({next: (value: any) => { called = true; }});
|
||||
emitter.emit(99);
|
||||
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
|
||||
it('delivers next and error events synchronously',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
const log: any[] /** TODO #9100 */ = [];
|
||||
|
||||
emitter.subscribe({
|
||||
next: (x: any) => {
|
||||
log.push(x);
|
||||
expect(log).toEqual([1, 2]);
|
||||
},
|
||||
error: (err: any) => {
|
||||
log.push(err);
|
||||
expect(log).toEqual([1, 2, 3, 4]);
|
||||
async.done();
|
||||
}
|
||||
});
|
||||
log.push(1);
|
||||
emitter.emit(2);
|
||||
log.push(3);
|
||||
emitter.error(4);
|
||||
log.push(5);
|
||||
}));
|
||||
|
||||
it('delivers next and complete events synchronously', () => {
|
||||
const log: any[] /** TODO #9100 */ = [];
|
||||
|
||||
emitter.subscribe({
|
||||
next: (x: any) => {
|
||||
log.push(x);
|
||||
expect(log).toEqual([1, 2]);
|
||||
},
|
||||
error: null,
|
||||
complete: () => {
|
||||
log.push(4);
|
||||
expect(log).toEqual([1, 2, 3, 4]);
|
||||
}
|
||||
});
|
||||
log.push(1);
|
||||
emitter.emit(2);
|
||||
log.push(3);
|
||||
emitter.complete();
|
||||
log.push(5);
|
||||
expect(log).toEqual([1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
it('delivers events asynchronously when forced to async mode',
|
||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||
const e = new EventEmitter(true);
|
||||
const log: any[] /** TODO #9100 */ = [];
|
||||
e.subscribe((x: any) => {
|
||||
log.push(x);
|
||||
expect(log).toEqual([1, 3, 2]);
|
||||
async.done();
|
||||
});
|
||||
log.push(1);
|
||||
e.emit(2);
|
||||
log.push(3);
|
||||
|
||||
}));
|
||||
|
||||
it('reports whether it has subscribers', () => {
|
||||
const e = new EventEmitter(false);
|
||||
expect(e.observers.length > 0).toBe(false);
|
||||
e.subscribe({next: () => {}});
|
||||
expect(e.observers.length > 0).toBe(true);
|
||||
});
|
||||
|
||||
// TODO: vsavkin: add tests cases
|
||||
// should call dispose on the subscription if generator returns {done:true}
|
||||
// should call dispose on the subscription on throw
|
||||
// should call dispose on the subscription on return
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user