我可以使用来自另一个可观察对象的多个事件来操纵一个observable吗?

时间:2015-12-04 15:59:12

标签: javascript rxjs

假设我有一组映射到输入字段的验证消息。假设我们从服务器获取这些验证消息。

我还有一个映射到输入字段的更改事件流。

每当我得到某个特定字段的更改事件时,我想

  1. 查看该字段是否有相应的验证消息
  2. 删除验证邮件
  3. 这是一个例子,希望能够说明为什么通常的嫌疑人(combineLatest,withLatestFrom)不会让我超过这条线。

    validating filtering stream

    combineLatest的问题是:第4个更改事件将过滤第2个验证数组。

    withLatestFrom的问题是:第三个更改事件将撤消第二个更改事件的工作。

    有没有人有任何提示?我吠叫错了树吗?我是否过度简化了问题?有一个RxJS方法是完美的吗?

3 个答案:

答案 0 :(得分:1)

每次有验证消息时,您似乎都在重新开始处理更改事件。在这种情况下,您可以尝试类似:

filteredValidation$ = validation$.flatMapLatest(function ( aObjs ) {
  return changeEvent$.scan(function ( acc, changeEvent ) {
    return isIn(changeEvent, acc) ? removeChangeEvent(changeEvent, acc) : acc;
  }, aObjs);
});

您必须根据isIn的特定形状编写removeChangeEventchange_event,但这很容易。

  • 每条验证邮件都会启动一个新流
  • 该流将具有由acc函数中的累加器scan表示的状态,该状态本身是最新的过滤验证对象。

我没有测试过,但希望它有效。

顺便说一句:我喜欢你的图表,它是你想要实现的处理的完美例证。

答案 1 :(得分:1)

这是另一种采用不同技术的答案。这个想法是相似的(使用scan来记住以前的值,但是我们从reduce函数中获取当前值,这取决于发出值的源。)

jsfiddle:http://jsfiddle.net/guc1tm4m/1

var ta_validation = document.getElementById('ta_validation');
var ta_change = document.getElementById('ta_change');
var ta_result = document.getElementById('ta_result');

function emits ( who, who_ ) {return function ( x ) {
 who.innerHTML = [who.innerHTML, who_ + " emits " + JSON.stringify(x)].join("\n");
};}

function isIn (changeEvent, prev){
  return !!prev[0][changeEvent];
}

function removeChangeEvent(changeEvent, prev) {
delete prev[0][changeEvent];
  return prev;
}

 var validation$ = Rx.Observable
 .fromEvent(document.getElementById('validation'), 'click')
 .map(function(_, index){
   var values=[
     [{a:'req', b:'req', c:'req'}],
           [{d:'req', e:'req'}],
           [{x:'req', y:'req', z:'req'}]
   ];
   return values[index % values.length];
   })
 .do(emits(ta_validation, 'validation'))
 .share();

var changeEvent$ = Rx.Observable
 .fromEvent(document.getElementById('change'), 'click')
 .map(function(_, index){
   console.log('ssds', index)
   var values=['x', 'a', 'b', 'z'];
   return values[index % values.length];
   })
 .do(emits(ta_change, 'change'))
 .share();

var filteredValidation$ = Rx.Observable
  .merge(validation$.map(function (x) {return function (  ) {return x;}}),
         changeEvent$.map(function ( changeEvent ) {
           return function ( prev ) {
             return isIn(changeEvent, prev) ? removeChangeEvent(changeEvent, prev) : prev;
           };
         }))
  .scan(function ( prev, f ) {
          return f(prev);
        }, {})
  .do(emits(ta_result, 'result'));

validation$.subscribe(function(){    });
changeEvent$.subscribe(function(){    });
filteredValidation$.subscribe(function(){    });

答案 2 :(得分:1)

我已经改编了上面的jsfiddle以显示我想出的解决方案。

jsfiddle:http://jsfiddle.net/hellosmithy/7kcoud2c/2/

基本上,此版本使用Rx.Observable.window根据来自changeEvents$流的新事件来整理validation$流。

var filteredValidation$ = validation$
    .merge(
        changeEvent$
        .window(validation$)
        .flatMapLatest(changeWindow => {
            return changeWindow.scan((acc, next) => acc.add(next), new Set());
        )
        .withLatestFrom(validation$, (filterSet, errs) => {
            return errs.filter(err => !filterSet.has(err.key));
        })
    )
    .distinctUntilChanged()