0

I have this scrolling div where if you scroll, it will clone the li tags and put them and the end so you have an infinite scroll. Here's the code for that:

infinite() {
  // it's a div, that holds your news
  // it holds ul with news in li elements
  const div = document.getElementById("container");
  div.addEventListener("scroll", function () {
    const maxScroll = this.scrollHeight - this.clientHeight;
    const currentScroll = this.scrollTop;
    const bottom = 100;
    if (currentScroll + bottom >= maxScroll) {
      const ul = document.getElementsByTagName("ul")[0];
      const current = parseInt(ul.dataset.current, 10);
      const li = document.querySelectorAll("li")[current];
      const newLi = li.cloneNode(true);
      ul.appendChild(newLi);
      ul.dataset.current = current + 1;
      console.log(li);
    }
  });
},

This works perfect for me. However, after the node is created, I can't put the event listener on the latest cloned li's because they are not in the DOM. How do I force the JS to put the event listener on newly cloned nodes? Here's the function for that:

 hover() {
  const rows = document.getElementsByClassName("plugin");
  rows.forEach((row) => {
    row.addEventListener("mouseover", () => {
      row.style.opacity = 1;
    });

    row.addEventListener("mouseout", () => {
      row.style.opacity = 0.3;
    });
  });
},
  • So add the events to the new elements Make a function, pass in the rows, add the events. – epascarello Nov 29 '21 at 15:36
  • You will need to add event using `e.target`, if target matches with the class than event will be applied else it is not. Or some other way that might I don't know – Rana Nov 29 '21 at 15:36
  • 3
    Real question... why are you not doing that in CSS. There is NO NEED for JavaScript. `#container li { opacity: 0.3; } #container li:hover { opacity: 1; }` – epascarello Nov 29 '21 at 15:37
  • Take a look at [Event Delegation](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) it solves the issue your having. It also drastically reduces the amount of event listeners you need. Or as commented above just use CSS – Reyno Nov 29 '21 at 15:43

1 Answers1

2

Just delegate

const ul = document.querySelector("#container ul");

ul.addEventListener("mouseover", e => {
  const tgt = e.target;
  if (tgt.tagName === "LI") tgt.style.opacity = 1;
})
ul.addEventListener("mouseout", e => {
  const tgt = e.target;
  if (tgt.tagName === "LI") tgt.style.opacity = .3;
});

or simply use CSS

#container li { opacity: .3 }    
#container li:hover { opacity: 1 }
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • 1
    CSS Solution should be the preferred approach, should have much better performance. – cloned Nov 29 '21 at 15:47
  • @cloned - sure - I gave the delegation version to replace what OP already had. Perhaps more processing was needed. CSS will always be faster – mplungjan Nov 29 '21 at 15:48
  • But here's the problem. I need to wait for my page to finish the animation and then I can hover, because basically I want to use setTimeout function on the hover, because the loading animation takes like 1s so I need to do this with a javascript instead of css – Spreceriany Nov 29 '21 at 18:05
  • My first code will work with or without the LIs in place. That is what delegation is – mplungjan Nov 29 '21 at 18:07
  • I get this error : Cannot set properties of undefined (setting 'opacity') – Spreceriany Nov 29 '21 at 18:36
  • This is the code: document.querySelector("ul").addEventListener("mouseover", (e) => { console.log(e.target.nodeName === "li"); if (e.target && e.target.nodeName === "li") { e.style.opacity = 1; } }); – Spreceriany Nov 29 '21 at 18:36
  • Because you changed it. Use tgt.closest("li") like I did – mplungjan Nov 29 '21 at 18:38
  • Perfection man! It worked! I just learned a new term event delegation! Thank you so much – Spreceriany Nov 29 '21 at 18:52
  • You WANT the div, that will handle ALL LIs under it – mplungjan Nov 29 '21 at 19:26
  • Yes, instead of the div I used the ul which holds all of the lis – Spreceriany Nov 29 '21 at 21:25
  • But you changed it back to the div, right? Because you have more than one ul – mplungjan Nov 30 '21 at 05:10
  • No, it's just basic ul that's holds li. The ul acts as a container, so there's only 1 ul tag and the li nodes are the ones that are duplicating. I found the code for that on stack overflow so if you copy the code I believe you can find It. – Spreceriany Nov 30 '21 at 07:46
  • Ah, sorry, You are correct. I thought you created a UL each time. So yes, delegate from the UL – mplungjan Nov 30 '21 at 07:53
  • You can move this outside the scroll event listener: `const ul = document.querySelector("#container ul");` – mplungjan Nov 30 '21 at 07:55