根据不同流的状态暂时累积对象

时间:2014-08-15 18:43:53

标签: javascript frp bacon.js

我一直试图通过在新项目中首先潜入FRP(以及bacon.js)来自学。我自己走得很远,但最近碰到了一个我似乎无法解决问题的问题:

我有一组带有一组可点击对象的界面。单击对象时,该对象的详细信息将加载到右侧的面板中。

我需要的是能够选择多个,将这些对象累积到一个数组中并显示一个"批量操作"选择多个时的面板。

到目前为止,我有:

  • 表示当前UI模式的SelectMultiple布尔属性
  • 包含当前所选对象的CurrentObject流

我对此有点接近:

var SelectedObjects = CurrentObject.filter(SelectMultiple).skipDuplicates().scan([], function(a,b){
    return a.concat([b]);
};

有一些问题:

  1. SelectedObjects的值表示选中的对象 所有这些,当SelectMultiple状态发生变化时,它不会重置。
  2. SelectObjects的值不包括原始值 CurrentObject(当然因为扫描累加器种子是一个 空数组,而不是CurrentObject的当前值。
  3. 我希望直接使用某个属性的当前值似乎暗示这里存在一个根本问题。我有一个概念,即每次SelectMultiple更改时,答案都涉及flapMapLatest并生成一个新流,将所选订单汇集到这个新流中并累积,但我无法理解应该是什么样的。

    当然还有一个问题,即skipDuplicates只跳过连续的重复项。我可以自己解决这个问题,但解决这个问题的解决方案是理想的。

    任何建议都将不胜感激!

2 个答案:

答案 0 :(得分:2)

这可能有效(coffeescript):

var selectMultiple # Property[Boolean] - whether in multiselect mode
var selectedObject # Property[Object] - latest selected object
var selectedObjects = selectMultiple.flatMapLatest((multiple) ->
  if !multiple
    selectedObject.map((obj) -> [obj])
  else
    selectedObject.scan([], (xs, x) ->
      xs.concat(x)
    )
).toProperty()

selectMultiple标记的每个值上,我们开始一个新流,它只是跟踪当前单个选择或从单个选择开始累积,添加项目,因为它们被选中。它不支持通过切换取消选择,但可以直接添加到scan部分。

答案 1 :(得分:0)

好的我找到了解决方案。我意识到我可以使用动态大小的slideWindow组合器。我在Implementing Snake in Bacon.js教程中找到了答案的基础。

当我尝试直接添加到Bacon原型时(我在教程中描述)我遇到了一个错误,所以我只创建了一个函数来获取流观察和一个确定它是否应该捕获值的布尔值:

slidingWindowWhile = function(sourceStream, toTakeOrNotToTake) {
    return new Bacon.EventStream(function(sink){
        var buf = [];
        var take = false;

        sourceStream.onValue(function(x){
            if (! take) {
                buf = [];
            }
            buf.push(x);
            sink(new Bacon.Next(buf));
        });

        toTakeOrNotToTake.onValue(function(v){
            take = v;
        });
    });
};

似乎应该有一种方法可以在不使用局部变量来跟踪状态的情况下执行此操作,但至少这个解决方案已经很好地封装了。