How to take first occurrence and then supress events for 2 seconds (RxJS)
Asked Answered
P

5

8

I think RxJS should perfectly fit to supress dublicate button clicks for 2 seconds. However, Im struggleing with the implementation.

var $button = $('#myButton').button();
$button
    .toObservable("click")
    //.Throttle(2000) // Wouldn't fire the first event instantly :-(
    .Subscribe(function(){ alert('clicked'); }); 

I already created a jsFiddle for your convenience. You need to scroll down in this fiddle, because I just pasted Rx inside as I couldn't find a CDN.

http://jsfiddle.net/cburgdorf/mUMFA/2/

Passkey answered 4/3, 2011 at 17:18 Comment(1)
Probably you can use xgrommx.github.io/rx-book/content/observable/… like bufferWithTimeOrCount(2000, 1)Nansen
P
5

I converted Sergeys answer into JavaScript and think this should be the final way to go.

var $button = $('#myButton').button();
    $button
        .toObservable("click")
        .Take(1)
        .Merge(Rx.Observable.Empty().Delay(2000))
        .Repeat()
        .Subscribe(function(){ console.log('clicked'); }

From my understanding this solutions is actually better because it doesn't rely on a sideeffect which makes it even better in terms of composability.

As Sergey pointed out, you could even go further and implement your own combinator like so:

Rx.Observable.prototype.OneInTime = function(delay){
 return this
        .Take(1)
        .Merge(Rx.Observable.Empty().Delay(delay))
        .Repeat();
};

So our example from above could be reduced to:

var $button = $('#myButton').button();
    $button
        .toObservable("click")
        .OneInTime(2000)
        .Subscribe(function(){ console.log('clicked'); });
Passkey answered 7/3, 2011 at 18:51 Comment(0)
F
3

This is how I would do it in RxNet (sorry, I'm not familiar with RxJS so not sure if it is possible there):

    public static IObservable<T> SupressDoubleClicks<T>(
        this IObservable<T> source, TimeSpan delay)
    {
        return source
            .Take(1)
            .Merge(Observable.Empty<T>().Delay(delay))
            .Repeat();
    }
Faradism answered 6/3, 2011 at 1:19 Comment(0)
P
2

Actually, Matthew from the Rx team was so kind to send me the answer via twitter: http://twitter.com/#!/mattpodwysocki/status/43731812513624064

So, what you can do is that:

var $button = $('#myButton').button();
$button
    .toObservable("click")
    .Do(function(){ 
        alert('clicked'); 
        $button.button('disable'); 
    })
    .Delay(2000)
    .Do(function(){ $button.button('enable'); })
    .Subscribe();   

http://jsfiddle.net/cburgdorf/mUMFA/5/

However: For exercice reasons. I would prefer to make it work without setting enable/disable but just supressing the events for 2 seconds after the first occurence

In marble speech, Im looking for this:

O Stream: X---X---X---X---X---X---X

RxStream: X------------X------------X

Passkey answered 4/3, 2011 at 18:47 Comment(0)
P
0

Crazy delicious!

I got it:

var $button = $('#myButton').button();
$button
    .toObservable("click")
    .Do(function(){ console.log('clicked'); })
    .Take(1)
    .Delay(2000)
    .Repeat()
    .Subscribe()
Passkey answered 5/3, 2011 at 21:5 Comment(0)
C
0

I learned a lot from this thread and actually the crazy delicious iteration is by far the cleanest. But I wanted to return a compose-able event stream -- like in the converted Sergeys answer. So here's my method...

Rx.Observable.prototype.throttleOnFirst = function(ms){

    var subject = new Rx.Subject();

    var throttler = this
        .do(function(data){subject.onNext(data)})
        .take(1)
        .delay(ms)
        .repeat()
        .subscribe()

    return subject;
};

Mine is in angular so I use it like this...

var goToChaseTrigger = $scope.$createObservableFunction('goToChase');
var throttleAfterFirst = goToChaseTrigger
    .throttleOnFirst(2000)
    .subscribe(function(d){console.log('throttleOnFirst>',d)})
Ceroplastic answered 12/12, 2014 at 20:8 Comment(1)
thumbs up for using the Angular Rx bindings :)Passkey

© 2022 - 2024 — McMap. All rights reserved.