[6a3a178] | 1 | import { Operator } from '../Operator';
|
---|
| 2 | import { Observable } from '../Observable';
|
---|
| 3 | import { Subscriber } from '../Subscriber';
|
---|
| 4 | import { OperatorFunction, MonoTypeOperatorFunction } from '../types';
|
---|
| 5 |
|
---|
| 6 | /* tslint:disable:max-line-length */
|
---|
| 7 | export function defaultIfEmpty<T>(defaultValue?: T): MonoTypeOperatorFunction<T>;
|
---|
| 8 | export function defaultIfEmpty<T, R>(defaultValue?: R): OperatorFunction<T, T | R>;
|
---|
| 9 | /* tslint:enable:max-line-length */
|
---|
| 10 |
|
---|
| 11 | /**
|
---|
| 12 | * Emits a given value if the source Observable completes without emitting any
|
---|
| 13 | * `next` value, otherwise mirrors the source Observable.
|
---|
| 14 | *
|
---|
| 15 | * <span class="informal">If the source Observable turns out to be empty, then
|
---|
| 16 | * this operator will emit a default value.</span>
|
---|
| 17 | *
|
---|
| 18 | * ![](defaultIfEmpty.png)
|
---|
| 19 | *
|
---|
| 20 | * `defaultIfEmpty` emits the values emitted by the source Observable or a
|
---|
| 21 | * specified default value if the source Observable is empty (completes without
|
---|
| 22 | * having emitted any `next` value).
|
---|
| 23 | *
|
---|
| 24 | * ## Example
|
---|
| 25 | * If no clicks happen in 5 seconds, then emit "no clicks"
|
---|
| 26 | * ```ts
|
---|
| 27 | * import { fromEvent } from 'rxjs';
|
---|
| 28 | * import { defaultIfEmpty, takeUntil } from 'rxjs/operators';
|
---|
| 29 | *
|
---|
| 30 | * const clicks = fromEvent(document, 'click');
|
---|
| 31 | * const clicksBeforeFive = clicks.pipe(takeUntil(interval(5000)));
|
---|
| 32 | * const result = clicksBeforeFive.pipe(defaultIfEmpty('no clicks'));
|
---|
| 33 | * result.subscribe(x => console.log(x));
|
---|
| 34 | * ```
|
---|
| 35 | *
|
---|
| 36 | * @see {@link empty}
|
---|
| 37 | * @see {@link last}
|
---|
| 38 | *
|
---|
| 39 | * @param {any} [defaultValue=null] The default value used if the source
|
---|
| 40 | * Observable is empty.
|
---|
| 41 | * @return {Observable} An Observable that emits either the specified
|
---|
| 42 | * `defaultValue` if the source Observable emits no items, or the values emitted
|
---|
| 43 | * by the source Observable.
|
---|
| 44 | * @method defaultIfEmpty
|
---|
| 45 | * @owner Observable
|
---|
| 46 | */
|
---|
| 47 | export function defaultIfEmpty<T, R>(defaultValue: R = null): OperatorFunction<T, T | R> {
|
---|
| 48 | return (source: Observable<T>) => source.lift(new DefaultIfEmptyOperator(defaultValue)) as Observable<T | R>;
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | class DefaultIfEmptyOperator<T, R> implements Operator<T, T | R> {
|
---|
| 52 |
|
---|
| 53 | constructor(private defaultValue: R) {
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | call(subscriber: Subscriber<T | R>, source: any): any {
|
---|
| 57 | return source.subscribe(new DefaultIfEmptySubscriber(subscriber, this.defaultValue));
|
---|
| 58 | }
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | /**
|
---|
| 62 | * We need this JSDoc comment for affecting ESDoc.
|
---|
| 63 | * @ignore
|
---|
| 64 | * @extends {Ignored}
|
---|
| 65 | */
|
---|
| 66 | class DefaultIfEmptySubscriber<T, R> extends Subscriber<T> {
|
---|
| 67 | private isEmpty: boolean = true;
|
---|
| 68 |
|
---|
| 69 | constructor(destination: Subscriber<T | R>, private defaultValue: R) {
|
---|
| 70 | super(destination);
|
---|
| 71 | }
|
---|
| 72 |
|
---|
| 73 | protected _next(value: T): void {
|
---|
| 74 | this.isEmpty = false;
|
---|
| 75 | this.destination.next(value);
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | protected _complete(): void {
|
---|
| 79 | if (this.isEmpty) {
|
---|
| 80 | this.destination.next(this.defaultValue);
|
---|
| 81 | }
|
---|
| 82 | this.destination.complete();
|
---|
| 83 | }
|
---|
| 84 | }
|
---|