00f551edf15aceca83bf4f55fbbecf5d14bedd49757a307795de7fd604b6af62a555750349df33d63365dbd611f4b53bc414cd13d14fcfde7fef85b996c724 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { Operator } from '../Operator';
  2. import { Subscriber } from '../Subscriber';
  3. import { Observable } from '../Observable';
  4. import { OperatorFunction, MonoTypeOperatorFunction, TeardownLogic } from '../types';
  5. /* tslint:disable:max-line-length */
  6. export function filter<T, S extends T>(predicate: (value: T, index: number) => value is S,
  7. thisArg?: any): OperatorFunction<T, S>;
  8. export function filter<T>(predicate: (value: T, index: number) => boolean,
  9. thisArg?: any): MonoTypeOperatorFunction<T>;
  10. /* tslint:enable:max-line-length */
  11. /**
  12. * Filter items emitted by the source Observable by only emitting those that
  13. * satisfy a specified predicate.
  14. *
  15. * <span class="informal">Like
  16. * [Array.prototype.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter),
  17. * it only emits a value from the source if it passes a criterion function.</span>
  18. *
  19. * ![](filter.png)
  20. *
  21. * Similar to the well-known `Array.prototype.filter` method, this operator
  22. * takes values from the source Observable, passes them through a `predicate`
  23. * function and only emits those values that yielded `true`.
  24. *
  25. * ## Example
  26. * Emit only click events whose target was a DIV element
  27. * ```ts
  28. * import { fromEvent } from 'rxjs';
  29. * import { filter } from 'rxjs/operators';
  30. *
  31. * const clicks = fromEvent(document, 'click');
  32. * const clicksOnDivs = clicks.pipe(filter(ev => ev.target.tagName === 'DIV'));
  33. * clicksOnDivs.subscribe(x => console.log(x));
  34. * ```
  35. *
  36. * @see {@link distinct}
  37. * @see {@link distinctUntilChanged}
  38. * @see {@link distinctUntilKeyChanged}
  39. * @see {@link ignoreElements}
  40. * @see {@link partition}
  41. * @see {@link skip}
  42. *
  43. * @param {function(value: T, index: number): boolean} predicate A function that
  44. * evaluates each value emitted by the source Observable. If it returns `true`,
  45. * the value is emitted, if `false` the value is not passed to the output
  46. * Observable. The `index` parameter is the number `i` for the i-th source
  47. * emission that has happened since the subscription, starting from the number
  48. * `0`.
  49. * @param {any} [thisArg] An optional argument to determine the value of `this`
  50. * in the `predicate` function.
  51. * @return {Observable} An Observable of values from the source that were
  52. * allowed by the `predicate` function.
  53. * @method filter
  54. * @owner Observable
  55. */
  56. export function filter<T>(predicate: (value: T, index: number) => boolean,
  57. thisArg?: any): MonoTypeOperatorFunction<T> {
  58. return function filterOperatorFunction(source: Observable<T>): Observable<T> {
  59. return source.lift(new FilterOperator(predicate, thisArg));
  60. };
  61. }
  62. class FilterOperator<T> implements Operator<T, T> {
  63. constructor(private predicate: (value: T, index: number) => boolean,
  64. private thisArg?: any) {
  65. }
  66. call(subscriber: Subscriber<T>, source: any): TeardownLogic {
  67. return source.subscribe(new FilterSubscriber(subscriber, this.predicate, this.thisArg));
  68. }
  69. }
  70. /**
  71. * We need this JSDoc comment for affecting ESDoc.
  72. * @ignore
  73. * @extends {Ignored}
  74. */
  75. class FilterSubscriber<T> extends Subscriber<T> {
  76. count: number = 0;
  77. constructor(destination: Subscriber<T>,
  78. private predicate: (value: T, index: number) => boolean,
  79. private thisArg: any) {
  80. super(destination);
  81. }
  82. // the try catch block below is left specifically for
  83. // optimization and perf reasons. a tryCatcher is not necessary here.
  84. protected _next(value: T) {
  85. let result: any;
  86. try {
  87. result = this.predicate.call(this.thisArg, value, this.count++);
  88. } catch (err) {
  89. this.destination.error(err);
  90. return;
  91. }
  92. if (result) {
  93. this.destination.next(value);
  94. }
  95. }
  96. }