diff --git a/spec/observables/fromEvent-spec.ts b/spec/observables/fromEvent-spec.ts index ef8f0bd531..4790e24fa1 100644 --- a/spec/observables/fromEvent-spec.ts +++ b/spec/observables/fromEvent-spec.ts @@ -115,6 +115,29 @@ describe('Observable.fromEvent', () => { expect(offHandler).to.equal(onHandler); }); + it('should pass through options to addEventListener', () => { + let actualOptions; + const expectedOptions = { capture: true, passive: true }; + + const obj = { + addEventListener: (a: string, b: EventListenerOrEventListenerObject, c?: any) => { + actualOptions = c; + }, + removeEventListener: (a: string, b: EventListenerOrEventListenerObject, c?: any) => { + //noop + } + }; + + const subscription = Observable.fromEvent(obj, 'click', expectedOptions) + .subscribe(() => { + //noop + }); + + subscription.unsubscribe(); + + expect(actualOptions).to.equal(expectedOptions); + }); + it('should pass through events that occur', (done: MochaDone) => { let send; const obj = { diff --git a/src/observable/FromEventObservable.ts b/src/observable/FromEventObservable.ts index 3c4fa4a6af..434a004f37 100644 --- a/src/observable/FromEventObservable.ts +++ b/src/observable/FromEventObservable.ts @@ -1,5 +1,6 @@ import {Observable} from '../Observable'; import {tryCatch} from '../util/tryCatch'; +import {isFunction} from '../util/isFunction'; import {errorObject} from '../util/errorObject'; import {Subscription} from '../Subscription'; import {Subscriber} from '../Subscriber'; @@ -34,6 +35,14 @@ function isEventTarget(sourceObj: any): sourceObj is EventTarget { export type EventTargetLike = EventTarget | NodeStyleEventEmmitter | JQueryStyleEventEmitter | NodeList | HTMLCollection; +export type EventListenerOptions = { + capture?: boolean; + passive?: boolean; + once?: boolean; +} | boolean; + +export type SelectorMethodSignature = (...args: Array) => T; + /** * We need this JSDoc comment for affecting ESDoc. * @extends {Ignored} @@ -41,6 +50,13 @@ export type EventTargetLike = EventTarget | NodeStyleEventEmmitter | JQueryStyle */ export class FromEventObservable extends Observable { + /* tslint:disable:max-line-length */ + static create(target: EventTargetLike, eventName: string): Observable; + static create(target: EventTargetLike, eventName: string, selector: SelectorMethodSignature): Observable; + static create(target: EventTargetLike, eventName: string, options: EventListenerOptions): Observable; + static create(target: EventTargetLike, eventName: string, options: EventListenerOptions, selector: SelectorMethodSignature): Observable; + /* tslint:enable:max-line-length */ + /** * Creates an Observable that emits events of a specific type coming from the * given event target. @@ -68,7 +84,8 @@ export class FromEventObservable extends Observable { * EventEmitter, NodeList or HTMLCollection to attach the event handler to. * @param {string} eventName The event name of interest, being emitted by the * `target`. - * @param {function(...args: any): T} [selector] An optional function to + * @parm {EventListenerOptions} [options] Options to pass through to addEventListener + * @param {SelectorMethodSignature} [selector] An optional function to * post-process results. It takes the arguments from the event handler and * should return a single value. * @return {Observable} @@ -78,28 +95,35 @@ export class FromEventObservable extends Observable { */ static create(target: EventTargetLike, eventName: string, - selector?: (...args: Array) => T): Observable { - return new FromEventObservable(target, eventName, selector); + options?: EventListenerOptions, + selector?: SelectorMethodSignature): Observable { + if (isFunction(options)) { + selector = options; + options = undefined; + } + return new FromEventObservable(target, eventName, selector, options); } constructor(private sourceObj: EventTargetLike, private eventName: string, - private selector?: (...args: Array) => T) { + private selector?: SelectorMethodSignature, + private options?: EventListenerOptions) { super(); } private static setupSubscription(sourceObj: EventTargetLike, eventName: string, handler: Function, - subscriber: Subscriber) { + subscriber: Subscriber, + options?: EventListenerOptions) { let unsubscribe: () => void; if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) { for (let i = 0, len = sourceObj.length; i < len; i++) { - FromEventObservable.setupSubscription(sourceObj[i], eventName, handler, subscriber); + FromEventObservable.setupSubscription(sourceObj[i], eventName, handler, subscriber, options); } } else if (isEventTarget(sourceObj)) { const source = sourceObj; - sourceObj.addEventListener(eventName, handler); + sourceObj.addEventListener(eventName, handler, options); unsubscribe = () => source.removeEventListener(eventName, handler); } else if (isJQueryStyleEventEmitter(sourceObj)) { const source = sourceObj; @@ -117,6 +141,7 @@ export class FromEventObservable extends Observable { protected _subscribe(subscriber: Subscriber) { const sourceObj = this.sourceObj; const eventName = this.eventName; + const options = this.options; const selector = this.selector; let handler = selector ? (...args: any[]) => { let result = tryCatch(selector)(...args); @@ -127,6 +152,6 @@ export class FromEventObservable extends Observable { } } : (e: any) => subscriber.next(e); - FromEventObservable.setupSubscription(sourceObj, eventName, handler, subscriber); + FromEventObservable.setupSubscription(sourceObj, eventName, handler, subscriber, options); } }