Создание фильтруемого списка с помощью RxJS

Я пытаюсь заняться реактивным программированием. Я постоянно использую функции массива, такие как карта, фильтрация и уменьшение, и мне нравится, что я могу манипулировать массивом без создания состояния.

В качестве упражнения я пытаюсь создать фильтруемый список с помощью RxJS, не вводя переменные состояния. В итоге должно получиться примерно так:

введите здесь описание изображениявведите здесь описание изображения

Я бы знал, как это сделать с помощью наивного JavaScript или AngularJS/ReactJS, но я пытаюсь сделать это только с помощью RxJS и без создания переменных состояния:

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() {}); 

Теперь, как я могу получить значение поиска в моей функции фильтра для наблюдаемого, который я создал из своего списка?

Большое спасибо за твою помощь!




Ответы (4)


Вам нужно будет обернуть from(list), так как ему нужно будет снова перезапускать наблюдаемый список каждый раз, когда фильтр изменяется. Так как это может случаться часто, вы также, вероятно, захотите предотвратить фильтрацию, когда фильтр слишком короткий или если есть еще одно нажатие клавиши в течение небольшого промежутка времени.

//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*/});

Все это адаптировано из одного из стандартных примеров для RxJS здесь

person paulpdaniels    schedule 29.05.2015

Вы можете создать новый поток, который берет список людей и поток ключей, объединяет их и сканирует, чтобы отфильтровать последний.

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)));

Таким образом, у вас будет:

-L------------------ список людей

------k-----k--k---- поток ключей

-L----k-----k--k---- объединенный поток

Затем вы можете отсканировать его. Как говорится в документах:

Rx.Observable.prototype.scan(накопитель, [начальное число])

Применяет функцию-аккумулятор к наблюдаемой последовательности и возвращает каждый промежуточный результат.

Это означает, что вы сможете фильтровать список, сохраняя новый список в аккумуляторе.

Как только вы подпишетесь, данные будут новым списком.

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

Надеюсь, это помогло / было достаточно ясно

person Felipe Skinner    schedule 30.04.2016


Вы также можете взглянуть на WebRx List-Projections.

Прямая демонстрация

Раскрытие информации: я являюсь автором Framework.

person Oliver Weichhold    schedule 31.05.2015