I'm trying to do a popup menu using RxJS, here is where I stopped: http://jsbin.com/coqulamamo/1/edit?html,js,output
I've mapped to 2 main eventstreams, menuActivation
and menuDeactivation
:
menuActivation
emits a popup container whenever any of its chidren emits mouseenter
or focusin
.menuDeactivation
emits the last menuActivation
element after its first mouseleave
or the next time any non-descendent element emits focusin
.For each popup container on menuActivation
, active
class is appended; For each on menuDeactivation
, active
class is removed from the element.
So far, so good. But now, how do I prevent too much DOM operations? There is no need to activate a menu when it is already active, the same applies to deactivations, but I don't want to keep states in a Rx.Subject, there can be any length of popup menus distributed on the page.
I tried .distinctUntilChanged()
but when a popup container is emitted sequentially in menuActivation
and then in menuDeactivation
, the next time the same popup won't be emitted on menuActivation
.
Is there a way to allow a popup container to surpass menuActivation.distinctUntilChanged()
after be project on menuDeactivation
?
distinctUntilChanged
can only work on a single observable. To work around this you can create an observable which combines your two observables. Something like
var menuAct2 = menuActivation.map(function(menu) { return { type: "act", menu: menu}; })
var menuDeact2 = menuDeactivation.map(function(menu) { return { type: "deact", menu: menu}; })
var actDeact = menuAct2.merge(menuDeact2)
.distinctUntilChanged(function (a) {return a;}, function (a, b) {
return a.menu === b.menu && a.type === b.type;
});
actDeact
.filter(function (a) { return a.type === "act";})
.map(function (a) {return a.menu;})
.subscribe(function(menu) {
console.log("Focou:", menu);
menu.classList.add("MainMenu__ListContainer--Active");
});
actDeact
.filter(function (a) { return a.type === "deact";})
.map(function (a) {return a.menu;})
.subscribe(function(menu) {
console.log("Desfocou:", menu);
menu.classList.remove("MainMenu__ListContainer--Active");
});
You basically create an observable by merging your two observables, do a distinctUntilChanged
on that observable, and split it back into two observables to use in the rest of your code.
Sorry if this is not proper javascript, I'm not too familiar with the language.