0
\$\begingroup\$

I would ideally like to add event listeners to a single group of elements, topLevelDesktopNavDropdownItems , in some kind of object syntax like {event: function, event: function}. Or is there another way to do this? Here is my current code:

topLevelDesktopNavDropdownItems.forEach( 
    element => element.addEventListener('mouseenter', topLevelNavItemMouseOver)
);

topLevelDesktopNavDropdownItems.forEach(
    element => element.addEventListener('mouseleave', topLevelNavItemMouseOut)
);

topLevelDesktopNavDropdownItems.forEach(
    element => element.addEventListener('keydown', topLevelNavItemLinkKeyDown)
);
\$\endgroup\$
2
\$\begingroup\$

Instead of iterating over the same array 3 times, iterate over it once:

topLevelDesktopNavDropdownItems.forEach((element) => {
  element.addEventListener('mouseenter', topLevelNavItemMouseOver);
  element.addEventListener('mouseleave', topLevelNavItemMouseOut);
  element.addEventListener('keydown', topLevelNavItemLinkKeyDown);
});

If you think that's too repetitive, you can put the listeners into an object and iterate over the object:

const handlers = {
  mouseenter: topLevelNavItemMouseOver,
  mouseleave: topLevelNavItemMouseOut,
  keydown: topLevelNavItemLinkKeyDown,
};
for (const element of topLevelDesktopNavDropdownItems) {
  for (const [event, handler] of Object.entries(handlers)) {
    element.addEventListener(event, handler);
  }
}

A couple suggestions regarding naming:

  • The mouseover event is not the same thing as the mouseenter event, Similarly, mouseleave is not exactly the same as mouseout. (One version propagates via bubbling/capturing, the other doesn't. If the elements have children, this makes a big difference.) For precision, consider naming the handlers exactly the same as the event they're listening for.

  • If you have lots of handlers like this, prefixing them all with topLevelNavItem may get undesirably verbose. To isolate their scope to hopefully make the prefixes less necessary, consider defining them inside a function:

const addDropdownListeners = () => {
  const mouseOverHandler = (event) => {
    // ...
  };
  // ...

Or define them inline with the object:

const dropdownHandlers = {
  mouseenter: (event) => {
    // ...
  }
  // ...
\$\endgroup\$
1
  • \$\begingroup\$ Thank you very much. This was all great stuff. I went with your first suggestion of only iterating over the array once, fixed my function names to use mouseenter/leave to reflect their true purpose, and tightened up my naming conventions a bit. Thank you again! \$\endgroup\$ – thenomadicmann Dec 4 '20 at 2:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.