Pete
Pete

Reputation: 3264

How to create a toggle stream in RxJS?

I'd like to create a steam that toggles based on keyup and keydown. The key code is emitted once on a keydown event and emitted again on the keyup event. I used distinctUntilChanged to prevent multiple key codes from being sent while keydown fires. The problem with my code is that I can't do successive keydown and keyup on the same key code because of the distinctUntilChanged.

Currently, pressing and releasing 'a' followed by 'b' works, but not 'a' followed by 'a'.

Requirements

What I want to achieve is:

Code

var getKeyCode = function(e) { return e.which; }
var target = document.querySelector('body');

var keyDownStream = Rx.Observable.fromEvent(target, 'keydown')
    .distinctUntilChanged(getKeyCode);

var keyUpStream = Rx.Observable.fromEvent(target, 'keyup')
    .distinctUntilChanged(getKeyCode);

var toggleStream = Rx.Observable.merge(keyDownStream, keyUpStream);

toggleStream.subscribe(function(e) {
    console.log(e.which);
});

Upvotes: 0

Views: 1286

Answers (2)

Pete
Pete

Reputation: 3264

Found the solution was to move the distinctUntilChanged to the merged observable and filter by event type and keycode. This would ensure that the subscribers are notified once for the keydown event and once for the keyup event for the same key.

var filterByTypeAndKeyCode = function(e) { return e.type + e.which; }
var target = document.querySelector('body');
var keyUpStream = Rx.Observable.fromEvent(target, 'keyup');
var keyDownStream = Rx.Observable.fromEvent(target, 'keydown');

Rx.Observable.merge(keyDownStream, keyUpStream)
    .distinctUntilChanged(filterByTypeAndKeyCode)
    .subscribe(function(e) {
        console.log(e.which);
    });

Upvotes: 1

user3743222
user3743222

Reputation: 18665

I used:

var toggleStream = Rx.Observable.fromEvent(document.body, 'keydown').filter(function ( e, index ) {
  return index < 1;
}).takeUntil(Rx.Observable.fromEvent(document.body, 'keyup')).repeat();

toggleStream.subscribe(function ( e ) {
 // the task should go here 
 console.log("key down :" + e.which);
});

You can find a jsbin here : http://jsbin.com/xuqasawese/edit?html,js,console,output

Currently, pressing and releasing 'a' followed by 'b' works, and also 'a' followed by 'a'. However, you can imagine that you press key 'a' and without releasing that key, press another one 'b' and release 'b'. Then press another key 'c', and your action will be executed. It's kind of an edge case, but do you have any intended behaviour should that happen?

Upvotes: 1

Related Questions