Search code examples
javascriptjqueryfrpbacon.js

Why does a Bacon.combineAsArray Stream of 'keyup' events immediately end?


I need to create a Bacon.Property that gets either true or false if multiple html input contain their correct char. (They all have to be correct, if not, the property needs to be false)

To achieve this, I created an Array of eventStreams via jquery.bacons asEventStream helper and used bacons combineAsArray to create a "allInputsAreCorrect" stream.

And this is when I fail. The "allInputsAreCorrect" immediatly ends. And after ending, it once calls my onValue callback (?). Did I get something completely wrong, or is their a better way to combine all those inputs into one Property?

Here are the corresponding parts from my code, I tried to comment everything as best as possible:

var phraseCorrect,
    phraseStream = Bacon.combineAsArray((function () {
        // Using jQuery.map to convert inputs
        // into an Array of eventStreams:
        return $('.keyphrase-list input')
            .map(mapFromInputToStream);
    }()));

// This is how I would like to create the Property..
// But the Stream doesnt fire, so this is unimportant for now.
phraseCorrect = phraseStream.toProperty(false);

phraseStream
    .onEnd(function () {
        // This gets called immediately..
        // And I dont get why.
        console.log('End?? Why????');
    });

phraseStream
    .onValue(function (values) {
        // This gets called **once**
        // (right after the onEnd logging.. ???)
        console.log('Gets called once', values);
    });

The mapping function that creates the keyup eventStreams:

function mapFromInputToStream() {
    var $input = $(this);

    // I commented out some mapping and filtering.
    // But even without `map` and `filter` it doesnt work.
    return $input
        .asEventStream('keyup');
        // .map(someMapping)
        // .filter(someFiltering);
}

This code logs the following:

End?? Why????
Gets called once [b.fn.b.init[17]]

(there are 17 inputs)

After that, typing anything in one of the html inputs doesnt trigger any callbacks.

I would appreciate if someone could give me an explanation for this behaviour (the immediatly ending stream). But of course, any hints on how to fix this (with bacon.js) are welcome..


Solution

  • Add a .get() or .toArray() so that you pass a real array to Bacon, not a jQuery object (that is returned by map). Bacon will mistake that for a constant (since it's not instanceof Array), and return an ended, constant property.

    var phraseCorrect = Bacon.combineAsArray($('.keyphrase-list input')
                                             .map(mapFromInputToStream)
                                             .get());