1 import { Observable } from '../Observable';
2 import { Operator } from '../Operator';
3 import { Subscriber } from '../Subscriber';
4 import { EmptyError } from '../util/EmptyError';
6 import { Observer, MonoTypeOperatorFunction, TeardownLogic } from '../types';
9 * Returns an Observable that emits the single item emitted by the source Observable that matches a specified
10 * predicate, if that Observable emits one such item. If the source Observable emits more than one such item or no
11 * items, notify of an IllegalArgumentException or NoSuchElementException respectively. If the source Observable
12 * emits items but none match the specified predicate then `undefined` is emitted.
14 * <span class="informal">Like {@link first}, but emit with error notification if there is more than one value.</span>
20 * import { range } from 'rxjs';
21 * import { single } from 'rxjs/operators';
23 * const numbers = range(1,5).pipe(single());
24 * numbers.subscribe(x => console.log('never get called'), e => console.log('error'));
31 * import { range } from 'rxjs';
32 * import { single } from 'rxjs/operators';
34 * const numbers = range(1,5).pipe(single(x => x === 10));
35 * numbers.subscribe(x => console.log(x));
42 * @see {@link findIndex}
43 * @see {@link elementAt}
45 * @throws {EmptyError} Delivers an EmptyError to the Observer's `error`
46 * callback if the Observable completes before any `next` notification was sent.
47 * @param {Function} predicate - A predicate function to evaluate items emitted by the source Observable.
48 * @return {Observable<T>} An Observable that emits the single item emitted by the source Observable that matches
49 * the predicate or `undefined` when no items match.
54 export function single<T>(predicate?: (value: T, index: number, source: Observable<T>) => boolean): MonoTypeOperatorFunction<T> {
55 return (source: Observable<T>) => source.lift(new SingleOperator(predicate, source));
58 class SingleOperator<T> implements Operator<T, T> {
59 constructor(private predicate?: (value: T, index: number, source: Observable<T>) => boolean,
60 private source?: Observable<T>) {
63 call(subscriber: Subscriber<T>, source: any): TeardownLogic {
64 return source.subscribe(new SingleSubscriber(subscriber, this.predicate, this.source));
69 * We need this JSDoc comment for affecting ESDoc.
73 class SingleSubscriber<T> extends Subscriber<T> {
74 private seenValue: boolean = false;
75 private singleValue: T;
76 private index: number = 0;
78 constructor(destination: Observer<T>,
79 private predicate?: (value: T, index: number, source: Observable<T>) => boolean,
80 private source?: Observable<T>) {
84 private applySingleValue(value: T): void {
86 this.destination.error('Sequence contains more than one element');
88 this.seenValue = true;
89 this.singleValue = value;
93 protected _next(value: T): void {
94 const index = this.index++;
97 this.tryNext(value, index);
99 this.applySingleValue(value);
103 private tryNext(value: T, index: number): void {
105 if (this.predicate(value, index, this.source)) {
106 this.applySingleValue(value);
109 this.destination.error(err);
113 protected _complete(): void {
114 const destination = this.destination;
116 if (this.index > 0) {
117 destination.next(this.seenValue ? this.singleValue : undefined);
118 destination.complete();
120 destination.error(new EmptyError);