使用 RxJS 创建可过滤列表
Creating a filterable list with RxJS
我正在尝试进入响应式编程。我一直使用 map、filter 和 reduce 等数组函数,并且喜欢我可以在不创建状态的情况下进行数组操作。
作为练习,我尝试在不引入状态变量的情况下使用 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() {});
现在如何将搜索值获取到我从列表创建的可观察对象的过滤函数中?
非常感谢您的帮助!
您需要包装 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 的标准示例之一 here
你可以在这里看看我是怎么做到的:
https://github.com/erykpiast/autocompleted-select/
它是端到端的解决方案,抓取用户交互并将过滤后的列表呈现给 DOM。
您也可以看看 WebRx's List-Projections。
披露:我是该框架的作者。
您可以创建一个新流,获取人员列表和 keyups 流,合并它们并扫描以过滤后者。
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---- keyups 流
-L----k-----k--k----合并流
然后就可以扫描了。正如文档所说:
Rx.Observable.prototype.scan(accumulator, [seed])
Applies an accumulator function over an observable sequence and returns each
intermediate result.
这意味着您将能够过滤列表,将新列表存储在累加器中。
订阅后数据为新列表。
people$.subscribe(data => console.log(data) ); //this will print your filtered list on console
希望它helps/was够清楚
我正在尝试进入响应式编程。我一直使用 map、filter 和 reduce 等数组函数,并且喜欢我可以在不创建状态的情况下进行数组操作。
作为练习,我尝试在不引入状态变量的情况下使用 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() {});
现在如何将搜索值获取到我从列表创建的可观察对象的过滤函数中?
非常感谢您的帮助!
您需要包装 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 的标准示例之一 here
你可以在这里看看我是怎么做到的: https://github.com/erykpiast/autocompleted-select/
它是端到端的解决方案,抓取用户交互并将过滤后的列表呈现给 DOM。
您也可以看看 WebRx's List-Projections。
披露:我是该框架的作者。
您可以创建一个新流,获取人员列表和 keyups 流,合并它们并扫描以过滤后者。
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---- keyups 流
-L----k-----k--k----合并流
然后就可以扫描了。正如文档所说:
Rx.Observable.prototype.scan(accumulator, [seed])
Applies an accumulator function over an observable sequence and returns each intermediate result.
这意味着您将能够过滤列表,将新列表存储在累加器中。
订阅后数据为新列表。
people$.subscribe(data => console.log(data) ); //this will print your filtered list on console
希望它helps/was够清楚