Reputation: 1476
I have a navigation with multiple event listeners: click
and hover
. This event listeners can change, e.g. on browser resize. I add the event listeners in my own method which gets called if listeners should be re-initialized. My problem in my following class: removeEventListener
does not work. So re-initialization causes that both click
and hover
fires.
class Navigation {
constructor(element) {
this.element = element;
this.changeButton = this.element.querySelector("button");
this.version = "hover";
this.navItemElements = Array.from(this.element.querySelectorAll(".nav-item"));
this.navItems = this.createNavItems(this.navItemElements);
this.clickHandler = (event) => this.navItemHoverHandler(event);
this.changeButton.addEventListener("click", () => {
this.isHoverVersion = !(this.isHoverVersion);
console.log("Change trigger. Is hover version --> " + this.isHoverVersion);
this.initListeners();
});
this.clickHandler = (event, navItem) => this.navItemClickHandler(event, navItem);
this.hoverHandler = (event, navItem) => this.navItemHoverHandler(event, navItem);
this.initListeners();
}
initListeners() {
console.log("Init listeners");
console.log(this.navItems);
if (this.isHoverVersion) {
this.navItems.forEach((navItem) => {
console.log(navItem);
navItem.link.addEventListener('mouseover', e => this.hoverHandler(e, navItem));
navItem.link.addEventListener('mouseout', e => this.hoverHandler(e, navItem));
navItem.link.removeEventListener('click',this.clickHandler);
})
} else {
this.navItems.forEach((navItem) => {
navItem.link.addEventListener('click', e => this.clickHandler(e, navItem));
navItem.link.removeEventListener('mouseover', this.hoverHandler);
navItem.link.removeEventListener('mouseout', this.hoverHandler);
})
}
}
navItemClickHandler(event, navItem) {
event.preventDefault();
console.log('Click handler executed');
console.log(navItem);
}
navItemHoverHandler(event, navItem) {
event.preventDefault();
console.log('Hover handler executed');
console.log(navItem);
}
createNavItems(navItemElements) {
let navItems = [];
navItemElements.forEach((itemElement) => {
navItems.push(this.createNavItemObject(itemElement));
});
return navItems;
}
createNavItemObject(navItem) {
let container = navItem;
let link = navItem.querySelector("a");
return {
container: container,
link: link,
};
}
}
let navigationElement = document.querySelector(".navigation");
new Navigation(navigationElement);
.navigation {
display: flex;
flex-flow: row nowrap;
width: 100%;
justify-content: space-between;
width: 100%;
max-width: 280px;
}
ul {
display: flex;
flex-flow: row nowrap;
list-style: none;
margin: 0;
padding: 0;
}
li {
margin-right: 20px;
}
<div class="navigation">
<button id="changeButton">Change trigger</button>
<ul>
<li class="nav-item">
<a href="">Link 1</a>
</li>
<li class="nav-item">
<a href="">Link 2</a>
</li>
</ul>
</div>
navItem
is an object, which I created before. navItem.link
is the HTML Anchor Element.
Question:
How can I bind the listener to the specific object?
I need to call the same method, but with its specific navItem
object...
Update:
Added working code example. The navigation gets initialized with click trigger. Clicking the button will toggle click / hover. In this example, after toggling from click to hover, both listeners get executed.
Upvotes: 2
Views: 285
Reputation: 1031
You need to use the exact function you used in addEventListener
, check the explanation on MDN.
So in your example you define a new anonymous function:
navItem.link.addEventListener('mouseout', e =>
this.hoverHandler(e, navItem)
);
The arrow function is the new anonymous function: e => ...
. So instead using this anonymous function you need to use the exact same function.
To get the navItem
in the event handler you can use bind()
. The first argument of bind defines the context (this
) in the event handler and all other arguments are preceding any provided (in this case the event
argument). But you should note that bind()
creates a new function reference every time, so you need to save the reference for the removing. One way to achieve this could be to save the function on the navItem
. For the hover
events it would be:
if (this.isHoverVersion) {
this.navItems.forEach(navItem => {
// save function
navItem.hoverHandler = this.navItemHoverHandler.bind(null, navItem);
navItem.link.addEventListener('mouseover', navItem.hoverHandler);
navItem.link.addEventListener('mouseout', navItem.hoverHandler);
});
} else {
this.navItems.forEach(navItem => {
navItem.link.removeEventListener('mouseover', navItem.hoverHandler);
navItem.link.removeEventListener('mouseout', navItem.hoverHandler);
});
}
Additionally you need to change your navItemHoverHandler
to this:
navItemHoverHandler(navItem, event) { // reversed order
event.preventDefault();
console.log('Hover handler executed');
console.log(navItem);
}
Upvotes: 1