0

Wracking my brains on this one but I'm sure it's just my inexperience with js.

I have a list of items and I am trying to create an eventListener for each item row so when I mouseover the row some icons will appear. The icons should hide again on mouseout.

I am using setAttribute to change the opacity of the elements on mouseover and mouseout events.

My problem is after the loop runs to create the eventListeners the setAttribute only affects the very last row of the loop - regardless of which row I mouse over.

I have a JSFiddle here which shows you the exact behaviour (better than I can explain): https://jsfiddle.net/Finno/ds9q7zju/27/

Note: this is a simplified example but it exhibits the same behaviour. My real app has the items formatted in a drop down menu.

Here is the code :

var total = 8;
var items;
var row;
var sort;
var trash;

for (var i = 0; i < total; i++) {
  items = items + '<div id="row' + i + '">';
  items = items + '<span class="hidden" id="sort' + i + '">SORT</span>';
  items = items + '<span id="content' + i + '">Some content</span>';
  items = items + '<span class="hidden" id="trash' + i + '">TRASH</span>';
  items = items + '</div><br>';
}
document.getElementById("queue").innerHTML = items;

for (var i = 0; i < total; i++) {
  row = 'row' + i;
  sort = 'sort' + i;
  trash = 'trash' + i;
  document.getElementById(row).addEventListener("mouseover", function() {
    document.getElementById(sort).setAttribute("style", "opacity:1 !important");
    document.getElementById(trash).setAttribute("style", "opacity:1 !important");
  });
  document.getElementById(row).addEventListener("mouseout", function() {
    document.getElementById(sort).setAttribute("style", "opacity:0 !important");
    document.getElementById(trash).setAttribute("style", "opacity:0 !important");
  });
}

Finno
  • 15
  • 1
  • 3
  • 1
    Why to bother, use [event delgation](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) instead. – Teemu May 25 '21 at 12:37
  • For that matter, use CSS instead. `:hover` effects are commonplace. Add a class like "queue-row" (or whatever) to your `div`, then, in CSS: `.queue-row .hidden {opacity: 0} .queue-row:hover .hidden { opacity: 1 }` – Heretic Monkey May 25 '21 at 12:48
  • You raise a good point @HereticMonkey - I should look into css `:hover` - it would be less taxing than eventListeners. But I don't want the whole row to hide, just some elements on the row that are triggered when hovering over the whole row. I'm not sure how to separate. – Finno May 25 '21 at 13:04
  • The code I posted does not hide the whole row. It hides elements with the "hidden" class in each row. – Heretic Monkey May 25 '21 at 13:06
  • Thanks for the link @Teemu. I don't know about this so I will check this out for sure. – Finno May 25 '21 at 13:13
  • 1
    @HereticMonkey - Thanks so much for your suggestion - I have now tested this and understand it. While the answer below is technically correct you directed me to a much better way to implement this and I learnt a better technique which I can now apply to my app. Many kudos - much appreciation! – Finno May 25 '21 at 23:44

1 Answers1

0

You need to recreate the variables in each iteration, Try this,

Also, you can use string interpolation in place of + to join strings

var total = 8;
var items;

for (var i = 0; i < total; i++) {
  items = items + '<div id="row' + i + '">';
  items = items + '<span class="hidden" id="sort' + i + '">SORT</span>';
  items = items + '<span id="content' + i + '">Some content</span>';
  items = items + '<span class="hidden" id="trash' + i + '">TRASH</span>';
  items = items + '</div><br>';
}
document.getElementById("queue").innerHTML = items;

for (var i = 0; i < total; i++) {
  let row = 'row' + i;
  let sort = 'sort' + i;
  let trash = 'trash' + i;
  document.getElementById(row).addEventListener("mouseover", function() {
    document.getElementById(sort).setAttribute("style", "opacity:1 !important");
    document.getElementById(trash).setAttribute("style", "opacity:1 !important");
  });
  document.getElementById(row).addEventListener("mouseout", function() {
    document.getElementById(sort).setAttribute("style", "opacity:0 !important");
    document.getElementById(trash).setAttribute("style", "opacity:0 !important");
  });
}
Ahmad Habib
  • 2,053
  • 1
  • 13
  • 28
Vivek Bani
  • 3,703
  • 1
  • 9
  • 18