ntaso
ntaso

Reputation: 614

RxJS listen to events but attach event listener later

With RxJS, I want to subscribe to events. The problem is: I want to setup the Observable BEFORE the event listener is set up.

Think of this like two buttons: Button1 does something when clicked, but only after button2 attached an event listener to button1. The observer should subscribe to the click event of button1. All of this should be wired together when the app starts. Button2 shouldn't setup the observer! Some code without RxJS:

button2.addEventListener('click', function() {
    // [...] some code to prevent that button1 has more than one event listener

    // attach event listener to button1
    button1.addEventListener('click', clickHandler);

    // now let observer subscribe itself to clickHandler somehow
    // -> HOW?
});


function clickHandler() {
    console.log("clicked");
}

Edit: Maybe, is it possible to observe some kind of dummy event handler that never emits anything, but turns into the real event handler (clickHandler) after button2 is clicked or something like that?!

Edit2: I noticed that the 2 buttons aren't the best example. Let's make it different and have the event listener for button2 be attached through some unknown mechanism. For example:

// is called by unkown means, i. e. the observer doesn't know how and when its attached
function attach() {
    button1.addEventListener('click', clickHandler);
}

But when attach() is called, the Observer should subscribe to the clickHandler. Or maybe the Observer is subscribed all the time to some function and attach() swaps out the function with the actual event listener. Dunno.

Upvotes: 3

Views: 4319

Answers (1)

cyr_x
cyr_x

Reputation: 14257

So as i understand you want to create an Observable which emits an item on each click of button1, but only after button2 was clicked some time before.

Then this should work:

var button1 = document.querySelector('#button1');
var button2 = document.querySelector('#button2');

var onButton2Click$ = Rx.Observable.fromEvent(button2, 'click').take(1);
var onButton1Click$ = Rx.Observable.fromEvent(button1, 'click').skipUntil(onButton2Click$);


onButton1Click$.subscribe(function(event) {
  console.log('button 1 clicked')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.min.js"></script>

<button id="button1">button 1</button>
<button id="button2">button 2</button>

It should be clear what the fromEvent method does.

The take operator with the parameter 1 ensures that the onButton2Click$ observable is only emitting 1 item and then completes.

The skipUntil operator ensures that the onButton1Click$ observable only starts emitting items until the onButton2Click$ observable emitted at least 1 item.

For the edited question:

var button1 = document.querySelector('#button1');
var button2 = document.querySelector('#button2');

var onAttach$$ = new Rx.Subject();

function attach() {
  onAttach$$.next();
  onAttach$$.complete();
}

var onButton1Click$ = Rx.Observable.fromEvent(button1, 'click').skipUntil(onAttach$$);

// for testing only
button2.addEventListener('click', function(e) {
  attach();
});

onButton1Click$.subscribe(function(event) {
  console.log('button 1 clicked')
});

onAttach$$.subscribe(function() { 
  console.log('attached listener')
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.3/Rx.min.js"></script>

<button id="button1">button 1</button>
<button id="button2">attach</button>

Upvotes: 7

Related Questions