Search code examples
javascriptlocomotive-scroll

Add class to the nearest element inside a foor loop


i'm trying to add class to an image looping into an Array. I have an array of elements settled with an document.querySelectorAll. When i hover into a single of this element i want to add a class to his image, but when hovering the only image with the class added in mouseover is only the first one (even if i mouseover the other two elements).

HTML:

<h2 class="wp-block-heading custom-font-h2 col-75 d-scroll has-large-font-size">Nato a NAPOLI<br>nel ‘92—Devoto a <span class="evidence">Reggie Miller</span> <img class="evidence-img" src="https://robertoacampora.it/wp-content/uploads/2023/05/reggie_miller_website_roberto_acampora.jpg">&amp; <span class="evidence">John Stockton</span><img class="evidence-img" src="https://robertoacampora.it/wp-content/uploads/2023/05/john-stockton_website_roberto_acampora.jpg"></h2>

Javascript:

let textevidences = document.querySelectorAll('.evidence');
    for(let textevidence of textevidences){

  textevidence.addEventListener('mouseover', MouseIn);
  function MouseIn(){
      let image = document.querySelector('.evidence-img');
      
      textevidence.image.classList.add('display'));
      console.log(textevidence.closest('img'));
  }

textevidence.addEventListener('mouseleave', MouseLeave);
 function MouseLeave(){
      let image = document.querySelector('.evidence-img');
      image.classList.remove('display');
  }
}

I also tried with this Js:

document.querySelectorAll('.evidence').forEach(element => {
  element.addEventListener('mouseover', () => {
      console.log('mouseover');
      let image = document.querySelector('.evidence-img');
      image.classList.add('display');
  });
});

// Remove class on mouseout
document.querySelectorAll('.evidence').forEach(element => {
  element.addEventListener('mouseout', () => {
      let image = document.querySelector('.evidence-img');
      image.classList.remove('display');
  });
});

The class added to all the single image near the class in hover, not only the first one image.


Solution

  • document.querySelector searches the whole page starting from the top and returns the first hit. Which in this case always is the first image. So that's not what you need.

    closest is meant to find the closest parent which matches the condition. So that's not what you need here either.

    What you probably want to use here is nextSibling, which returns the next sibling element. In your HTML you have a space between the span and the img, so the nextSibling after the span will actually be a TextElement with that space, and not the image. But maybe you want to put some more stuff in between the two anyway.

    To find the next image after each span, you can iterate over all sibling elements after that span, until you find one with the image class.

    let textevidences = document.querySelectorAll('.evidence');
    
    for (let textevidence of textevidences) {
      let evidenceImage = textevidence.nextSibling;
      while (evidenceImage && !evidenceImage.classList?.contains("evidence-img")) {
          evidenceImage = evidenceImage.nextSibling;
      }
      // Now either we have the image in evidenceImage, or we've reached the last sibling without finding an image, in which case evidenceImage is undefiend.
      
      if (!evidenceImage) {
        break;
      }
    
      textevidence.addEventListener('mouseover', () => {
        evidenceImage.classList.add("display");
      });
      
      textevidence.addEventListener('mouseleave', () => {
        evidenceImage.classList.remove("display");
      });
    }