Search code examples
javascriptjqueryloops

Javascript : Looping through elements in a changing array


I have a webpage with a form that i want to reorganize. All the fields are in one <table>, and to reorder it, i created other tables. I want now to dispatch the fields of the first table given a certain condition. My problem is, as i loop through my elements and moving them, the javascript array is changing, hence missing some items.

What would be the best way to achieve my goal ?

Before :

<table id='tableForm'><tbody>
  <tr><td>Some Input to stay here</td></tr>
  <tr><td>Some Input to stay here</td></tr>
  <tr><td>Some Input to move to tab1</td></tr>
  <tr><td>Some Input to move to tab2</td></tr>
  <tr><td>Some Input to stay here</td></tr>
  <tr><td>Some Input to move to tab2</td></tr>
  <tr><td>Some Input to move to tab1</td></tr>
</tbody></table>

<table id='tab1'>
  <tbody></tbody>
</table>
<table id='tab2'>
  <tbody></tbody>
</table>

(yes, there is no class nor id to select elements, only based on innerText)

After :

<table id='tableForm'><tbody>
  <tr><td>Some Input to stay here</td></tr>
  <tr><td>Some Input to stay here</td></tr>
  <tr><td>Some Input to stay here</td></tr>
</tbody></table>
<table id='tab1'><tbody>
  <tr><td>Some Input to move to tab1</td></tr>
  <tr><td>Some Input to move to tab2</td></tr>
</tbody></table>
<table id='tab2'><tbody>
  <tr><td>Some Input to move to tab2</td></tr>
  <tr><td>Some Input to move to tab2</td></tr>
</tbody></table>

So far i've made :

var toMove = {
  'Input to move to tab1' : 'tab1',
  'Input to move to tab2' : 'tab2',
}
$('table#tableForm')[0].firstChild.childNodes.forEach((c) => {
  content = $(c).find('td')[0].innerText
  if (toMove[content]) {
    $('#'+toMove[content]).appendTo(c)  // <= This change *.childNodes, next iteration will miss the next element
  }
});

Given the nature of Javascript, the iterator will not go through every element. As we are removing some from the node, the next element take the place of the current and will be missed by the next iteration.

I could do some magic with complexes is and js but is there any simple way to achieve that ?


Solution

  • You can always shallow copy an iterable before looping if you mutate it:

    [...$('table#tableForm')[0].firstChild.childNodes].forEach((c) => {
      content = $(c).find('td')[0].innerText
      if (toMove[content]) {
        $('#'+toMove[content]).appendTo(c)  // <= This change *.childNodes, next iteration will miss the next element
      }
    });