skip to Main Content

Bellow is a very short code which sorts each span into a new array depending on the className it has.

What I currently have: As soon as a square of a specified class is hovered – IT GETS a color unique to its class.

What I needed to acheive: As soon as one of a specified class is hovered – ALL classList ITEMS GET the unique color of their class.

Can someone tell me what is wrong in the code bellow?
Thank you!

let allDivs = [...document.querySelectorAll(`div`)];
let Classes = [ "A0", "A1", "A2", "A3" ];

console.log(`let 'allDivs' equals:`);
console.log(allDivs);

for (let i = 0; i < Classes.length; i++) {
  let allDivsFiltered = allDivs.filter(item => (item.className.match(`A${i}`)));

  console.log('---- ---- ---- ----');
  console.log(`let 'allDivsFiltered [${i}]' equals:`);
  console.log(allDivsFiltered);

  // allDivsFiltered.classList.add(`B${i}`); // THIS DOESN'T WORK;

  for (let all of allDivsFiltered) {
    all.onmouseover = () => {
      all.classList.add(`B${i}`); // This does work,
      // but seperately on each one;

      // allDivsFiltered.classList.add(`B${i}`); // DOESN'T WORK HERE
        // AS WELL;
    };

    console.log(all);
  };
};
body {
  display: flex;
  flex-wrap: wrap;
}

div[class^="A"] {
  position: relative;
  background-color: slategray;
  width: 100px;
  height: 100px;
  top: 0px;
  left: 0px;
  margin-top: 4px;
  margin-left: 4px;
}

div[class^="A"].B0 {
  background-color: red;
}

div[class^="A"].B1 {
  background-color: blue;
}

div[class^="A"].B2 {
  background-color: green;
}

div[class^="A"].B3 {
  background-color: yellow;
}
<div class="A0"></div>
<div class="A0"></div>
<div class="A0"></div>
<div class="A1"></div>
<div class="A1"></div>
<div class="A2"></div>
<div class="A2"></div>
<div class="A3"></div>
<div class="A3"></div>

3

Answers


  1. You’d need to loop over allDivsFiltered in your mouseover handler and add the class to each one. Right now you’re only adding the class to the hovered element.

    I’d organise the code a little differently by bucketing each filtered collection and adding a common class to indicate a hovered / active state.

    const classes = ['A0', 'A1', 'A2', 'A3'];
    
    const elements = classes.reduce(
      (map, c) => map.set(c, document.querySelectorAll(`.${c}`)),
      new Map(),
    );
    
    document.addEventListener('mouseover', ({ target }) => {
      target.classList.forEach((c) => {
        elements.get(c)?.forEach((e) => e.classList.add('active'));
      });
    });
    body {
      display: flex;
      flex-wrap: wrap;
    }
    
    div {
      position: relative;
      background-color: slategray;
      width: 100px;
      height: 100px;
      top: 0px;
      left: 0px;
      margin-top: 4px;
      margin-left: 4px;
    }
    
    .A0.active {
      background-color: red;
    }
    
    .A1.active {
      background-color: blue;
    }
    
    .A2.active {
      background-color: green;
    }
    
    .A3.active {
      background-color: yellow;
    }
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A1"></div>
    <div class="A1"></div>
    <div class="A2"></div>
    <div class="A2"></div>
    <div class="A3"></div>
    <div class="A3"></div>
    Login or Signup to reply.
  2. You’re almost there. Just loop over allDivsFiltered to add or remove the class.

    I also simplified your query into a single step.

    let Classes = ["A0", "A1", "A2", "A3"];
    
    Classes.forEach((className, i) => {
      let allDivsFiltered = document.querySelectorAll(`div.${className}`);
    
      allDivsFiltered.forEach(div => {
        div.onmouseover = () => {
          allDivsFiltered.forEach(div => div.classList.add(`B${i}`));
        };
    
        div.onmouseout = () => {
          allDivsFiltered.forEach(div => div.classList.remove(`B${i}`));
        };
      });
    });
    body {
      display: flex;
      flex-wrap: wrap;
    }
    
    div {
      position: relative;
      background-color: slategray;
      width: 100px;
      height: 100px;
      top: 0px;
      left: 0px;
      margin-top: 4px;
      margin-left: 4px;
    }
    
    .B0 {
      background-color: red;
    }
    
    .B1 {
      background-color: blue;
    }
    
    .B2 {
      background-color: green;
    }
    
    .B3 {
      background-color: yellow;
    }
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A1"></div>
    <div class="A1"></div>
    <div class="A2"></div>
    <div class="A2"></div>
    <div class="A3"></div>
    <div class="A3"></div>
    Login or Signup to reply.
  3. I think instead of add toggle is suitable.

    let allDivs = [...document.querySelectorAll(`div`)];
    let classes = [ "A0", "A1", "A2", "A3" ];
    
    classes.forEach(className => {
      const elementsWithClass = document.querySelectorAll(`.${className}`);
    
      elementsWithClass.forEach(element => {
        element.addEventListener('mouseover', () => {
          elementsWithClass.forEach(element => element.classList.toggle(`B${className.slice(1)}`));
        });
    
        element.addEventListener('mouseout', () => {
          elementsWithClass.forEach(element => element.classList.remove(`B${className.slice(1)}`));
        });
      });
    });
    body {
      display: flex;
      flex-wrap: wrap;
    }
    
    div {
      position: relative;
      background-color: slategray;
      width: 100px;
      height: 100px;
      top: 0px;
      left: 0px;
      margin-top: 4px;
      margin-left: 4px;
    }
    
    .B0 {
      background-color: red;
    }
    
    .B1 {
      background-color: blue;
    }
    
    .B2 {
      background-color: green;
    }
    
    .B3 {
      background-color: yellow;
    }
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A0"></div>
    <div class="A1"></div>
    <div class="A1"></div>
    <div class="A2"></div>
    <div class="A2"></div>
    <div class="A3"></div>
    <div class="A3"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search