1 import { Operator } from '../Operator';
2 import { Observable } from '../Observable';
3 import { Subscriber } from '../Subscriber';
4 import { Subscription } from '../Subscription';
5 import { ObservableInput, OperatorFunction, ObservedValueOf } from '../types';
6 import { map } from './map';
7 import { from } from '../observable/from';
8 import { SimpleOuterSubscriber, SimpleInnerSubscriber, innerSubscribe } from '../innerSubscribe';
10 /* tslint:disable:max-line-length */
11 export function switchMap<T, O extends ObservableInput<any>>(project: (value: T, index: number) => O): OperatorFunction<T, ObservedValueOf<O>>;
12 /** @deprecated resultSelector is no longer supported, use inner map instead */
13 export function switchMap<T, O extends ObservableInput<any>>(project: (value: T, index: number) => O, resultSelector: undefined): OperatorFunction<T, ObservedValueOf<O>>;
14 /** @deprecated resultSelector is no longer supported, use inner map instead */
15 export function switchMap<T, R, O extends ObservableInput<any>>(project: (value: T, index: number) => O, resultSelector: (outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R): OperatorFunction<T, R>;
16 /* tslint:enable:max-line-length */
19 * Projects each source value to an Observable which is merged in the output
20 * Observable, emitting values only from the most recently projected Observable.
22 * <span class="informal">Maps each value to an Observable, then flattens all of
23 * these inner Observables.</span>
27 * Returns an Observable that emits items based on applying a function that you
28 * supply to each item emitted by the source Observable, where that function
29 * returns an (so-called "inner") Observable. Each time it observes one of these
30 * inner Observables, the output Observable begins emitting the items emitted by
31 * that inner Observable. When a new inner Observable is emitted, `switchMap`
32 * stops emitting items from the earlier-emitted inner Observable and begins
33 * emitting items from the new one. It continues to behave like this for
34 * subsequent inner Observables.
37 * Generate new Observable according to source Observable values
39 * import { of } from 'rxjs';
40 * import { switchMap } from 'rxjs/operators';
42 * const switched = of(1, 2, 3).pipe(switchMap((x: number) => of(x, x ** 2, x ** 3)));
43 * switched.subscribe(x => console.log(x));
54 * Rerun an interval Observable on every click event
56 * import { fromEvent, interval } from 'rxjs';
57 * import { switchMap } from 'rxjs/operators';
59 * const clicks = fromEvent(document, 'click');
60 * const result = clicks.pipe(switchMap((ev) => interval(1000)));
61 * result.subscribe(x => console.log(x));
64 * @see {@link concatMap}
65 * @see {@link exhaustMap}
66 * @see {@link mergeMap}
67 * @see {@link switchAll}
68 * @see {@link switchMapTo}
70 * @param {function(value: T, ?index: number): ObservableInput} project A function
71 * that, when applied to an item emitted by the source Observable, returns an
73 * @return {Observable} An Observable that emits the result of applying the
74 * projection function (and the optional deprecated `resultSelector`) to each item
75 * emitted by the source Observable and taking only the values from the most recently
76 * projected inner Observable.
80 export function switchMap<T, R, O extends ObservableInput<any>>(
81 project: (value: T, index: number) => O,
82 resultSelector?: (outerValue: T, innerValue: ObservedValueOf<O>, outerIndex: number, innerIndex: number) => R,
83 ): OperatorFunction<T, ObservedValueOf<O>|R> {
84 if (typeof resultSelector === 'function') {
85 return (source: Observable<T>) => source.pipe(
86 switchMap((a, i) => from(project(a, i)).pipe(
87 map((b, ii) => resultSelector(a, b, i, ii))
91 return (source: Observable<T>) => source.lift(new SwitchMapOperator(project));
94 class SwitchMapOperator<T, R> implements Operator<T, R> {
95 constructor(private project: (value: T, index: number) => ObservableInput<R>) {
98 call(subscriber: Subscriber<R>, source: any): any {
99 return source.subscribe(new SwitchMapSubscriber(subscriber, this.project));
104 * We need this JSDoc comment for affecting ESDoc.
108 class SwitchMapSubscriber<T, R> extends SimpleOuterSubscriber<T, R> {
110 private innerSubscription?: Subscription;
112 constructor(destination: Subscriber<R>,
113 private project: (value: T, index: number) => ObservableInput<R>) {
117 protected _next(value: T) {
118 let result: ObservableInput<R>;
119 const index = this.index++;
121 result = this.project(value, index);
123 this.destination.error!(error);
126 this._innerSub(result);
129 private _innerSub(result: ObservableInput<R>) {
130 const innerSubscription = this.innerSubscription;
131 if (innerSubscription) {
132 innerSubscription.unsubscribe();
134 const innerSubscriber = new SimpleInnerSubscriber(this);
135 const destination = this.destination as Subscription;
136 destination.add(innerSubscriber);
137 this.innerSubscription = innerSubscribe(result, innerSubscriber);
138 // The returned subscription will usually be the subscriber that was
139 // passed. However, interop subscribers will be wrapped and for
140 // unsubscriptions to chain correctly, the wrapper needs to be added, too.
141 if (this.innerSubscription !== innerSubscriber) {
142 destination.add(this.innerSubscription);
146 protected _complete(): void {
147 const {innerSubscription} = this;
148 if (!innerSubscription || innerSubscription.closed) {
154 protected _unsubscribe() {
155 this.innerSubscription = undefined;
158 notifyComplete(): void {
159 this.innerSubscription = undefined;
160 if (this.isStopped) {
165 notifyNext(innerValue: R): void {
166 this.destination.next!(innerValue);