1

What I have is

<div>
 <div onclick="find(this)" class="grey">1</div>
 <div onclick="find(this)" class="grey">2</div>
 <div onclick="find(this)" class="grey">3</div>
 <div onclick="find(this)" class="grey">4</div>
 <div onclick="find(this)" class="grey">5</div>
</div>

What I like to do is to click on a <div> (for example:<div>...3</div>) and replace the class for div 3 and all it's previous sibling 'red' and all next sibling 'grey'.

What I thought would work is to loop backwards till it reaches the parent element.

What I've been trying.

function find(ele) {
 var active = ele;
 var previous = active.previousElementSibling;
 var next = active.nextElementSibling;
 var list = [];  // Trying to find a way to push all previous siblings of active into this array
 var i = 0;
 while (i < list){
  next.classList.replace('grey')
  previous.classList.replace('red');
  i++
 }
}

With insufficient knowledge to complete my function there is a few undefined that I need help with, but after thinking through, this function might not work because everytime the function is called previous sibling will return to grey.

So it there a way to make this work?

Like only elements in the list array replace class to red and those not in the array replace to grey.

Thank you for your help, really appreciate whoever you are for the help.

jon.c
  • 25
  • 5

1 Answers1

3

I'd put all the target divs into an array first. On click, find the index of the clicked element in the array with indexOf. Then, you can .slice the array from index 0 to the clicked index, setting all elements inside that slice to red - then, .slice again, but this time starting from the clicked index, and set all elements of that slice to grey:

const greys = [...document.querySelectorAll('.grey')];

function find(ele) {
  const index = greys.indexOf(ele);
  greys.slice(0, index + 1).forEach((prevElm) => {
    prevElm.className = 'red';
  });
  greys.slice(index + 1).forEach((nextElm) => {
    nextElm.className = 'grey';
  });
}
.red {
  background-color: red;
}
.grey {
  background-color: yellow;
}
<div>
  <div onclick="find(this)" class="grey">1</div>
  <div onclick="find(this)" class="grey">2</div>
  <div onclick="find(this)" class="grey">3</div>
  <div onclick="find(this)" class="grey">4</div>
  <div onclick="find(this)" class="grey">5</div>
</div>

Also note that inline handlers have very weird behavior, and should be avoided whenever possible. Consider attaching the listeners properly using Javascript instead:

const greys = [...document.querySelectorAll('.grey')];
greys.forEach((elm) => {
  elm.addEventListener('click', () => find(elm));
});

function find(ele) {
  const index = greys.indexOf(ele);
  greys.slice(0, index + 1).forEach((prevElm) => {
    prevElm.className = 'red';
  });
  greys.slice(index + 1).forEach((nextElm) => {
    nextElm.className = 'grey';
  });
}
.red {
  background-color: red;
}
.grey {
  background-color: yellow;
}
<div>
  <div class="grey">1</div>
  <div class="grey">2</div>
  <div class="grey">3</div>
  <div class="grey">4</div>
  <div class="grey">5</div>
</div>

Could also use event delegation instead, so that you only have to attach one listener, rather than 5 separate ones:

const greys = [...document.querySelectorAll('.grey')];
const container = document.querySelector('div');
container.addEventListener('click', ({ target }) => {
  if (target.parentElement === container) {
    find(target);
  }
});

function find(ele) {
  const index = greys.indexOf(ele);
  greys.slice(0, index + 1).forEach((prevElm) => {
    prevElm.className = 'red';
  });
  greys.slice(index + 1).forEach((nextElm) => {
    nextElm.className = 'grey';
  });
}
.red {
  background-color: red;
}
.grey {
  background-color: yellow;
}
<div>
  <div class="grey">1</div>
  <div class="grey">2</div>
  <div class="grey">3</div>
  <div class="grey">4</div>
  <div class="grey">5</div>
</div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • the code worked perfectly and I thank you so much for that. there are a few things I'm struggling to understand but I'll try to look into it. – jon.c Feb 29 '20 at 06:24
  • Yes, `const` should always be preferred over the other ways of declaring variables - it makes code much easier to read. – CertainPerformance Feb 29 '20 at 06:27