Creating a Filtered List Using RxJS

I am trying to get into reactive programming. I use array functions such as map, filter and reduce all the time and love that I can manipulate arrays without creating a state.

As an exercise, I am trying to create a filtered list with RxJS without introducing state variables. In the end, it should work something like this:

enter image description hereenter image description here

I would know how to do this with naive JavaScript or AngularJS / ReactJS, but I am trying to do this only with RxJS and without creating state variables:

var list = [ 'John', 'Marie', 'Max', 'Eduard', 'Collin' ]; Rx.Observable.fromEvent(document.querySelector('#filter'), 'keyup') .map(function(e) { return e.target.value; }); // i need to get the search value in here somehow: Rx.Observable.from(list).filter(function() {}); 

Now, how do I get the search value in my filter function on an observable that I created from my list?

Many thanks for your help!

+5
source share
4 answers

You will need to wrap from(list) , because each time you change the filter, you will need to restart the list that is observed again. Since this can happen a lot, you also probably want to prevent filtering when the filter is too short, or if there is another key turn for a short period of time.

 //This is a cold observable we'll go ahead and make this here var reactiveList = Rx.Observable.from(list); //This will actually perform our filtering function filterList(filterValue) { return reactiveList.filter(function(e) { return /*do filtering with filterValue*/; }).toArray(); } var source = Rx.Observable.fromEvent(document.querySelector('#filter'), 'keyup') .map(function(e) { return e.target.value;}) //The next two operators are primarily to stop us from filtering before //the user is done typing or if the input is too small .filter(function(value) { return value.length > 2; }) .debounce(750 /*ms*/) //Cancel inflight operations if a new item comes in. //Then flatten everything into one sequence .flatMapLatest(filterList); //Nothing will happen until you've subscribed source.subscribe(function() {/*Do something with that list*/}); 

All this is adapted from one of the standard examples for RxJS here

+5
source

You can create a new stream that accepts a list of people and a stream of keys, combines them and scans to filter the latter.

 const keyup$ = Rx.Observable.fromEvent(_input, 'keyup') .map(ev => ev.target.value) .debounce(500); const people$ = Rx.Observable.of(people) .merge(keyup$) .scan((list, value) => people.filter(item => item.includes(value))); 

This way you will have:

-L ------------------ list of people

------ k ----- k - k ---- keyups stream

-L ---- k ----- k - k ---- combined flow

Then you can scan it. As the docs say:

Rx.Observable.prototype.scan (battery, [seed])

Applies the battery function in the observed sequence and returns each intermediate result.

This means that you can filter the list by saving the new list to the battery.

Once you are subscribed, the data will be new.

 people$.subscribe(data => console.log(data) ); //this will print your filtered list on console 

Hope this helps / is clear enough.

+1
source

You can see how I did it: https://github.com/erykpiast/autocompleted-select/

This solution is end to end, capturing user interactions and filtering out the DOM list.

0
source

You can also see WebRx List-Projections .

Live demo

Disclosure . I am the author of Framework.

0
source

All Articles