使用来自另一个observable的值过滤可观察对象

时间:2013-07-19 11:54:09

标签: rxjs reactive-extensions-js

我有两个可观察者:

  1. 表示复选框输入列表的observable。
  2. 表示来自服务器的事件流的observable。
  3. 我想使用第一个值中的值来过滤第二个observable。

    从服务器接收的值包括tag属性,该属性对应于复选框列表中的值。上述两者的组合产生的可观察性只会产生服务器的值,其tag属性包含在勾选复选框中。

4 个答案:

答案 0 :(得分:31)

您可以使用withLatestFromenter image description here

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

此处,checkboxes是一个表示复选框输入列表的observable。 source是一个可观察的,表示来自服务器的事件流。在过滤功能中,您可以检查数据是否与复选框设置相比有效,并让它通过。

请注意,在流可以发出任何内容之前,checkboxes至少会发出至少1个值。

聚苯乙烯。关于其他答案,即使源为cold,此解决方案仍然有效。

答案 1 :(得分:6)

为了使用流B的值过滤流A,您需要观察流B并使用最新值来过滤流A.

使用switch()将B observable转换为A observable的可观察产生值。

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

使用switch()假设dataSourcehot observable

使用interval()生成虚拟数据的示例:



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'>
&#13;
&#13;
&#13;

此示例将生成类似于:

的输出
in: c
in: a
out: a
in: b
in: c
out: a
in: b
in: a

in反映所有生成的输入,b反映通过过滤器的数据。通过选中反映值&#34; a&#34;,&#34; b&#34;的复选框输入来调整过滤器。和&#34; c&#34;。

答案 2 :(得分:2)

显然,我需要的是selectfilterswitchLatest的组合。我写了一个小的测试用例来证明这一点:https://gist.github.com/igstan/d5b8db7b43f49dd87382#file-observable-filter-observable-js-L36-L45

答案 3 :(得分:0)

扩展@Dorus 的回答...在 Kotlin 中,您可以这样做:

val observable: Observable<Data> = ...
val filter: Observable<Checkbox> = ...
val filtered: Observable<Data> =
        observable.filterWithLatestFrom(filter) { checkbox -> checkbox.isSelected }

使用扩展功能:

/**
 * Return an [Observable] with type [T1] that is filtered using the last event emitted by the [other] observable.
 */
fun <T1 : Any, T2 : Any> Observable<T1>.filterWithLatestFrom(other: Observable<T2>, filterFunction: (T2) -> Boolean)
: Observable<T1> {
    return this.withLatestFrom(other) { obs1, obs2 -> Pair(obs1, obs2) }
        .filter { (_, obs2) -> filterFunction.invoke(obs2) }
        .map { (obs1, _) -> obs1}
}