Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter an observable using values from another observable

I have two observables:

  1. An observable representing a list of checkbox inputs.
  2. An observable representing a stream of events coming from the server.

I'd like to filter the second observable using values from the first one.

The values received from the server include a tag property, which corresponds to values in the checkbox list. The observable resulted from the combination of the above two would only yield values from the server whose tag property is included in the set of ticked checkboxes.

like image 333
Ionuț G. Stan Avatar asked Jul 19 '13 11:07

Ionuț G. Stan


People also ask

How do you use the result of one Observable in another?

For transforming items emitted by an Observable into another Observable, you probably want to use the flatMap operator. It creates an inner Observable and flats its result to the outer stream. const source = this. myService .

Does Observable have next?

There is no next() on Observable; only on Subject and BehaviorSubject, which extends Subject (and both extend Observable).

What is Observable subscribe?

Subscribing to an Observable is like calling a function, providing callbacks where the data will be delivered to. This is drastically different to event handler APIs like addEventListener / removeEventListener . With observable. subscribe , the given Observer is not registered as a listener in the Observable.

What are Observable methods?

Observables provide support for passing messages between parts of your application. They are used frequently in Angular and are a technique for event handling, asynchronous programming, and handling multiple values.


2 Answers

You can use withLatestFrom. enter image description here.

source.withLatestFrom(checkboxes, (data, checkbox) => ({data, checkbox}))   .filter(({data, checkbox}) => ...) 

Here, checkboxes is an observable representing a list of checkbox inputs. source is an observable representing a stream of events coming from the server. In the filter function you can check if the data is valid compared to the checkbox settings and let it trough.

Notice it is important checkboxes emits at least 1 value before the stream can emit anything.

Ps. In regard to other answers, this solution works even if the source is cold.

like image 166
Dorus Avatar answered Sep 18 '22 06:09

Dorus


In order to filter stream A using values of stream B, you need to observe stream B and use the latest values to filter stream A.

Use switch() to transform B observable to an observable producing values from A observable.

checkedInputValuesSource     .map(function (options) {         return dataSource             .filter(function (value) {                 return options.indexOf(value) !== -1;             });     })     .switch()     .subscribe(function (x) {         console.log('out: ' + x);     }); 

Using switch() assumes that dataSource is a hot observable.

Example using interval() to produce dummy data:

var input,      checkedInputValuesSource,      dataSource;    input = document.querySelectorAll('input');    // Generate source describing the current filter.  checkedInputValuesSource = Rx.Observable      .fromEvent(input, 'change')      .map(function () {          var inputs = document.querySelectorAll('input'),              checkedInputValues = [];                    [].forEach.call(inputs, function (e) {              if (e.checked) {                  checkedInputValues.push(e.value);              }          });                    return checkedInputValues;      })      .startWith([]);    // Generate random data source (hot).  dataSource = Rx.Observable      .interval(500)      .map(function () {          var options = ['a', 'b', 'c'];                return options[Math.floor(Math.floor(Math.random() * options.length))];      })      .do(function (x) {          console.log('in: ' + x);      })      .share();    checkedInputValuesSource      .map(function (options) {          return dataSource              .filter(function (value) {                  return options.indexOf(value) !== -1;              });      })      .switch()      .subscribe(function (x) {          console.log('out: ' + x);      });
<script src='https://rawgit.com/Reactive-Extensions/RxJS/v.2.5.3/dist/rx.all.js'></script>    <input type='checkbox' value='a'>  <input type='checkbox' value='b'>  <input type='checkbox' value='c'>

This example will produce output similar to:

in: c in: a out: a in: b in: c out: a in: b in: a 

Where in reflects all generated input and b the data that passes the filter. Filter is adjusted by checking the checkbox inputs, that reflect values "a", "b" and "c".

like image 34
Gajus Avatar answered Sep 21 '22 06:09

Gajus