Search code examples
javascriptjqueryfrpbacon.js

How can I temporarily "block" an EventStream in bacon.js using another stream?


I'm trying to wrap my head around FRP concepts and build an image slider using bacon.js. I'm mapping the next button's (this is a contrived example btw) click stream like:

var position = $slideshow.find('.next').asEventStream('click').map(function(){
    return 1;
}).scan(0, function(x,y){
    return x + y < $slideshow.find('.slide').length ? (x + y) : 0;
});

position.onValue(function(val){
    //set things
});

This works fine. Now I would like to disable clicking of my slideshow while it is advancing to the next slide. All ways that I could think of include the creation of a state variable that I feed to skipWhile like:

var isAnimating = false;
var position = $slideshow.find('.next').asEventStream('click').map(function(){
    return 1;
}).skipWhile(isAnimating).scan(0, function(x,y){
    return x + y < $slideshow.find('.slide').length ? (x + y) : 0;
});

position.onValue(function(val){
    isAnimating = true;
    //set things
});

This feels like cheating (especially when doing FRP "excercises"...) so I was wondering if there is any way I could combine my click stream with a stream of animation end events:

var animationEndStream = $slideshow.asEventStream('animationend');

Solution

  • If you manage to capture animation end events as an EventStream, say animEndE, you can now define the "is animating" state as a Property as in

    var animEndE = $slideshow.asEventStream('animationend')
    var nextE = $slideshow.find('.next').asEventStream('click')
    var prevE = $slideshow.find('.next').asEventStream('click')
    var moveE = nextE.map(1).merge(prevE.map(-1))
    
    var animatingP = moveE.awaiting(animEndE)
    var position = moveE.filter(animatingP.not()).scan(0, function(x,y) { return x+y })
    

    As you can see, I'm filtering the moveE stream based on the negation of animatingP.