007
007

Reputation: 2186

JS - mouseover and mouseout events are inconstant

HTML

<a class="level-item like-icon">
    <div class="icon is-medium">
        <i class="far fa-heart" onmouseover="change(true)" onmouseout="change(false)"></i>
    </div>
</a>

JS

change = (state) => {
    state
        ? event.currentTarget.setAttribute('data-prefix', 'fas')
        : event.currentTarget.setAttribute('data-prefix', 'far');
};

Goal:
To change icon (class, or in this case, attribute) when someone hovers over the icon and revert it back when the user hovers out of it. The above code seems to work but there are a couple issues. 1) It fires way to many times when I hover over it and 2) Many times, it doesn't change the attribute back to "far" (state = false). I tried attaching those events to <a> instead of <li> but the issues persist.

p.s. NOT using JQUERY

Upvotes: 1

Views: 862

Answers (4)

Hac&#232;ne
Hac&#232;ne

Reputation: 273

Here is a second version of my initial answer, this time with multiple elements.

var elements = document.getElementsByClassName("hover-icon");
var i;
for (i = 0; i < elements.length; i++) {
	element = elements[i];
  element.addEventListener('mouseover', function(data) {
  	console.log('Mouse over, set Font Awesome of ID ' + data.originalTarget.id + " here");
});

element.addEventListener('mouseout', function(data) {
  console.log('Mouse out, remove Font Awesome of ID ' + data.originalTarget.id  + " here");
});
} 

var event = new MouseEvent('mouseover', {
  'view': window,
  'bubbles': true,
  'cancelable': true
});
<a class="level-item like-icon">
    <div class="icon is-medium">
        <i id="hoverIcon1" class="hover-icon far fa-heart">ICON1</i>
        <i id="hoverIcon2" class="hover-icon far fa-heart">ICON2</i>
    </div>
</a>

Upvotes: 1

Brian Peacock
Brian Peacock

Reputation: 1849

There are 7 'onmouse...' events...

onmousedown, 
onmouseenter, 
onmouseleave, 
onmousemove, 
onmouseout, 
onmouseover, 
onmouseup

... so it is important to use the right one for the job.

In the example clicking and mouse movement within the Element doesn't apply - all we want is a function to be called once when the mouse enters and the element and once agian when the mouse leaves. Therefore...

<!-- HTML -->

<a class="level-item like-icon">
    <div class="icon is-medium">
        <i class="far fa-heart" 
           onmouseenter="change(this)"
           onmouseleave="change(this)"></i>
    </div>
</a>

So here it seems sensible to use the onmouseenter and onmouseleave attributes to call the change() function, and in this case to passes the HTML Element under the mouse as an argument via the this keywords.

Now the function can scrutinize the element and check if it has the desired and required 'data-prefix' attribute, and if so what that attribute is set to. We can then use this condition to set/reset the 'data-prefix' attribute's value...

/* JavaScript */

change = (elem) => {
    // does the Element have a 'data-prefix' attribute
    // and what is it set to?
    let isSet = elem.hasAttribute("data-prefix") && (
        "far" === elem.getAttribute("data-prefix")
    );
    elem.setAttribute("data-prefix", (isSet ? "fas" : "far"));
}

However, as has already been mentioned using the Element.addEventListener() method is more robust and flexible than relying on HTML attributes like onmouse....

Upvotes: 1

Stranger in the Q
Stranger in the Q

Reputation: 3898

Something like this one ?

Here i adding and removing a class hover, but ti also may be any attribute or something else

window.addEventListener('mousemove', e => {
  let hovered = document.querySelector('.hover');
  if (e.target === hovered) return;
  if (hovered) { 
    console.log('mouse out from', hovered);
    hovered.classList.remove('hover');
  }
  if (!e.target.classList.contains('icon')) 
    return;
  e.target.classList.add('hover');
  console.log('mouse over on', e.target)
})
.icon {
  display: inline-block;
  width: 50px;
  height: 50px;
  transition: 100ms;
  border: solid;
  text-align: center;
  line-height: 50px;
}

.hover {
   color: red;
   border-radius: 30%;
   transform: rotate(10deg)
}
<div class="icon">1</div>
<div class="icon">2</div>
<div class="icon">3</div>
<div class="icon">4</div>
<div class="icon">5</div>
<div class="icon">6</div>
<div class="icon">7</div>

Upvotes: 2

Hac&#232;ne
Hac&#232;ne

Reputation: 273

This sounds like a duplicate of How do I simulate a mouseover in pure JavaScript that activates the CSS ":hover"?

It's not ideal to deal with mouseover in pure JS, but here is a working example (insipired by an answer to the post I linked).

var element = document.getElementById('hoverIcon');
element.addEventListener('mouseover', function() {
  console.log('Mouse over, set Font Awesome class here');
});

element.addEventListener('mouseout', function() {
  console.log('Mouse out, remove Font Awesome class here');
});

var event = new MouseEvent('mouseover', {
  'view': window,
  'bubbles': true,
  'cancelable': true
});
<a class="level-item like-icon">
    <div class="icon is-medium">
        <i id="hoverIcon" class="far fa-heart">ICON</i>
    </div>
</a>

Upvotes: 1

Related Questions