There is an array of objects. A table is drawn on the base of the array. enter image description here

The task is to get the first and last id values ​​for the color segment by clicking on the cell. If you make a click as shown in the picture, then the values ​​"c9" and "d31" must be obtained. Also for any other segment. I tried to define an element in the array by clicking, and from it to use while back and forth, until the color of the next cell matches the current one. Then we write down id. But something does not go out. That does not work, then the eternal cycle begins. Maybe while generally a bad idea. I would appreciate the help

let arr = [ { id: 'm2c', color: 'yellow' }, { id: 'd1b', color: 'red' }, { id: 'd6', color: 'red' }, { id: 'd3', color: 'red' }, { id: 'd4', color: 'red' }, { id: 'd5', color: 'yellow' }, { id: 'd6', color: 'yellow' }, { id: 'd7', color: 'yellow' }, { id: 'v1', color: 'yellow' }, { id: 'c9', color: 'red' }, { id: 'd1k', color: 'red' }, { id: 'd92', color: 'red' }, { id: 'd12', color: 'red' }, { id: 'd31', color: 'red' }, { id: 'd14', color: 'yellow' }, { id: 'd12', color: 'yellow' }, { id: 'd45', color: 'yellow' }, { id: 'd3', color: 'yellow' }, { id: 'd00', color: 'yellow' }, { id: 'd3o', color: 'yellow' }, ]; let ul = document.createElement('ul'); let startId = document.createElement('span'); let endId = document.createElement('span'); arr.forEach(function (item) { let li = document.createElement('li'); li.style.backgroundColor = item.color; li.innerHTML = item.id; ul.appendChild(li); }); document.getElementById('container').appendChild(ul); document.getElementById('container').appendChild(startId ); document.getElementById('container').appendChild(ul); document.querySelector('ul').addEventListener('click', e => { let content = e.target.innerHTML; let startIdValue; let endIdValue; arr.forEach(function (item, i, arr) { if (item.id === content) { while (arr[i--]) { if (arr[i - 1].color !== item.color) { startIdValue = item.id; return } } while (arr[i++]) { if (arr[i + 1].color !== item.color) { endIdValue = item.id; return } } } }); }); 
  ul { width: 1000px; padding-left: 0; margin-left: 0; display: flex; } li { width: 50px; height: 50px; list-style-type: none; border: 1px solid #ccc; } 
 <div id="container"> </div> 

    4 answers 4

    The code below is purely a search function, without an interface (so as not to obstruct the code) at the entrance — the ID of the element from the segment. at the exit - a segment. how to click in the cell and get the ID, to further transfer to the function, I think, and so it is known.

     let arr = [ { id: 'm2c', color: 'yellow' }, { id: 'd1b', color: 'red' }, { id: 'd6', color: 'red' }, { id: 'd3', color: 'red' }, { id: 'd4', color: 'red' }, { id: 'd5', color: 'yellow' }, { id: 'd6', color: 'yellow' }, { id: 'd7', color: 'yellow' }, { id: 'v1', color: 'yellow' }, { id: 'c9', color: 'red' }, { id: 'd1k', color: 'red' }, { id: 'd92', color: 'red' }, { id: 'd12', color: 'red' }, { id: 'd31', color: 'red' }, { id: 'd14', color: 'yellow' }, { id: 'd12', color: 'yellow' }, { id: 'd45', color: 'yellow' }, { id: 'd3', color: 'yellow' }, { id: 'd00', color: 'yellow' }, { id: 'd3o', color: 'yellow' } ]; function findRange(needle){ var l = r = idx = arr.findIndex( v => v.id == needle); var color = arr[idx].color; while(l && arr[l].color == color) l--; while(r < arr.length && arr[r].color == color) r++; return arr.slice(l+1,r); } var result = findRange('d14'); console.log(result); 

    • I used your decision. It seemed to me the most concise. And to get from it the first and last value of the segment as simple as possible. The only thing that does not take into account the case when we have a segment has an element with index 0. Decided it is so return! L? arr.slice (l, r): arr.slice (l + 1, r); - pridan 2:51 pm

    Try to think in this direction:

     document.querySelector('ul').addEventListener('click', e => { var content = e.target.innerHTML; var startIdValue; var endIdValue; // давай найдем для начала индекс элемента, на который ткнули var currentIndex = arr.findIndex(el => el.id === content); // затем найдем его цвет var currentColor = arr[currentIndex].color; // в цикле for началом отсчета зададим найденный индекс элемента // перебор будет осуществляться до тех пор, пока крайний цвет перестанет быть currentColor for (let i = currentIndex, arr[i].color == currentColor, i--) { // в конечном счете присвоится то, что нужно // здесь можешь выполнять какие-то дополнительные условия перед тем как присваивать, например найти цвет предыдущего айтема, если false - значит приехали - присваиваем startIdValue = arr[i].id } // аналогично здесь, только перебор по возрастанию for (let i = currentIndex, arr[i].color == currentColor, i++) { endIdValue = arr[i].id } }); 

      Ohh ... it was hard))

      DEMO - JsFiddle

      First, add this piece after your array:

       let g = 1; arr[0].group = g; for(let i=1; i< arr.length; i++){ if( arr[i].color !== arr[i-1].color ){ g += 1; } arr[i].group = g; } 

      The idea is to group all the objects in the array that have the same color. To avoid errors with undefined elements of the array, at first the object immediately shoved arr[0].group = g; , further launched a loop that checks on each lap. If the color of the current element !== does not match the color of the previous one, add +1 to the previously created variable. On each circle we add to the next object a new attribute arr[i].group = g;

      Further. In your forEach added this piece:

       li.dataset.group = item.group; li.className = 'moo moo' + item.group; 

      The first line means that each li element in HTML will be added.
      data-group="число" attribute (from where it will be possible to get this number through the same элемент.dataset.group ), at the same time in the second line I add classes to click to attach to them. One common moo, the second - depending on the number in item.group , in order to somehow group them in classes.

      If you look at the source code, it will look like this:

      And finally he registered a click:

       let moo = document.getElementsByClassName('moo'); for(let i = 0; i < moo.length; i++){ moo[i].addEventListener('click',function(){ let data = 'moo' + this.dataset.group; let thisMoo = document.getElementsByClassName(data); document.getElementById('demo').innerHTML = thisMoo[0].innerHTML + ', ' + thisMoo[thisMoo.length-1].innerHTML; }); } 

      Click on the moo class, through the loop. First created let data - to get the class of the group we need. Accordingly, the let thisMoo class let thisMoo through the data variable Remains the case for small))

      The first value will be thisMoo[0].innerHTML
      And the second is thisMoo[thisMoo.length-1].innerHTML

      Then he realized that everything could be reduced in places, but already too lazy to redo it) Maybe if you get into the idea, you can write it down better. [although with the code of this type you can get not only the first and last values ​​... but any, already by classes] Well, you will need to add a condition in case the first value matches the last one (single cell).

      Ps later revised the question and it turned out that I was an idiot and didn’t decide at all)) Although the result is the same.

         let arr = [ { id: 'm2c', color: 'yellow' }, { id: 'd1b', color: 'red' }, { id: 'd6', color: 'red' }, { id: 'd3', color: 'red' }, { id: 'd4', color: 'red' }, { id: 'd5', color: 'yellow' }, { id: 'd6', color: 'yellow' }, { id: 'd7', color: 'yellow' }, { id: 'v1', color: 'yellow' }, { id: 'c9', color: 'red' }, { id: 'd1k', color: 'red' }, { id: 'd92', color: 'red' }, { id: 'd12', color: 'red' }, { id: 'd31', color: 'red' }, { id: 'd14', color: 'yellow' }, { id: 'd12', color: 'yellow' }, { id: 'd45', color: 'yellow' }, { id: 'd3', color: 'yellow' }, { id: 'd00', color: 'yellow' }, { id: 'd3o', color: 'yellow' } ]; const list = document.createElement('ul'); list.innerHTML = arr.map(v => `<li style="background-color: ${v.color};">${v.id}</li>` ).join(''); document.body.appendChild(list); list.addEventListener('click', e => { if (!(e.target instanceof HTMLLIElement)) return; const targetClr = e.target.style.backgroundColor, siblings = [...e.target.parentElement.children]; const checkColor = el => el && (el.style.backgroundColor === targetClr); let left, right; left = right = siblings.indexOf(e.target); while (checkColor(siblings[left - 1])) left--; while (checkColor(siblings[right + 1])) right++; console.clear(); console.log(`Отрезок: ${siblings[left].textContent}..${siblings[right].textContent}`); }); 
         ul { list-style: none; display: flex; padding: 0; } li { flex: 0 0 50px; font: 1rem/50px sans-serif; text-align: center; box-shadow: 0 0 0 1px #ccc; }