0

I am trying to make this more abstract. I need to find a way to use one function for the same element and different events. I would also like to be able to pass in an element argument but I know I can't do this with a callback. This is what I have thus far:

const divElement = document.querySelector('#test');
    
divElement.addEventListener(
  'mouseenter',
  (event) => {
    divElement.classList.add('shadow');
    console.log(event);
  },
  false
);
    
divElement.addEventListener(
  'mouseleave',
  (event) => {
    divElement.classList.remove('shadow');
    console.log(event);
  },
  false
);
2
  • 1
    Why not a css hover style? example Commented Nov 9, 2021 at 20:35
  • Yes, I can do that but I wanted to try it with JS. I know we should opt for CSS every time, if we can. JS is sometimes overkill. However, this is a poor example. I just wanted to make something more abstract and follow the DRY principle and use a more abstract approach. I am just learning JS for the first time. I am a backend developer. Commented Nov 10, 2021 at 13:37

3 Answers 3

2

Use CSS instead. Never use JS for what can be achieved in CSS.

#test {
  background-color: white;
  padding: 30px;
  transition: all 0.4s ease;
}

#test:hover {
  box-shadow: 0 0 10px #000;
}
<div id="test">
  Lorem ipsum dolor sit amentur.
</div>

If for some reason you didn't reveal you need it to be event-listener-based, here's what I would do:

const divElement = document.querySelector('#test');
function handleMouseAction({type}) {
  this.classList.toggle('shadow', type === 'mouseenter');
}

divElement.addEventListener('mouseenter', handleMouseAction, false);
divElement.addEventListener('mouseleave', handleMouseAction, false);
#test {
  padding: 30px;
  transition: all 0.4s ease;
}

.shadow {
  box-shadow: 0 0 10px #000;
}
<div id="test">
  Lorem ipsum dolor sit amentur.
</div>

Sign up to request clarification or add additional context in comments.

4 Comments

I have a couple of questions. Why the curly brackets { type } ? Also,, how would I pass an element into this function instead of hard coding "divElement" ?
The { type } syntax is called object destructuring and means "from the object passed, give me the value of the type property of that object, as a local variable named type". You don't need to pass the element, you can access it using this. I've adjusted my second code example accordingly.
I get what you're saying. I should have guessed it would be "this" but I'm used to other languages where "this" and "self" refer to a method or property of a class.
Event listeners passed to addEventListener get bound to the element the listener is attached to (unless you use an arrow function).
1

You can write a helper function and call that from the two callbacks:

const divElement = document.querySelector('#test');
function handleEvent(event, action) {
  divElement.classList[action]('shadow');
  console.log(event);
}

divElement.addEventListener('mouseenter', (event) => handleEvent(event, 'add'), false);
divElement.addEventListener('mouseleave', (event) => handleEvent(event, 'remove'), false);

Alternatively, you can use partial application with closures to create the two callbacks from one abstract function:

const divElement = document.querySelector('#test');
function makeEventHandler(action) {
  return (event) => {
    divElement.classList[action]('shadow');
    console.log(event);
  };
}

divElement.addEventListener('mouseenter', makeEventHandler('add'), false);
divElement.addEventListener('mouseleave', makeEventHandler('remove'), false);

Of course @Wyck is right and in this particular example, you should do everything with CSS only :-)

9 Comments

While JS allows this, it is certainly a bad programming practice. I've also coded like that in the past, but in many code reviews and discussions I dropped it because it makes code harder to refactor.
@connexo What in particular is a bad practice? I assume OP wants to learn about the techniques how to simplify event handlers, not specifically make a hover shadow.
classList[action]
@connexo I don't see what's so hard to refactor about that. Another option would be classList.toggle('shadow', flag) with a boolean flag parameter, but I prefer a two-value string enum for clarity.
@connexo Ah, that's a nice approach as well. Have an upvote!
|
-1

My way to do that:

const divElement = document.querySelector('#test');
const events = ["mouseenter", "mouseleave"]

events.forEach(event => {
    divElement.addEventListener(event, (e) => {
       // TODO put logic here.
       divElement.classList.add('shadow');
       console.log(event);
   })
})

Another way to do that, by using onmouseenter="" tag and onmouseleave="" tag, and letting them use the same callback.

const callback = (element) => {
   element.classList.add("shadow");
}
.shadow {
  display: block;
  box-shadow: 0 0 10px black;
}
<div onmouseenter="callback(this)" onmouseleave="callback(this)">Hello World</div>

4 Comments

Isn't calling JS functions inside the HTML sort of deprecated?
No it's not deprecated as I know.
I'm new to JS. I just thought it would be easier to separate all the JS from the HTML.
I did like the foreach example as well. Thank you everyone.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.