Search code examples
javascriptecmascript-6ecmascript-2016ecmascript-next

Detect TD element by inner value and move it to be last


Trying to better my skills with ECMAScript with moving elements and their content. Regarding my scenario, Once the DOM is ready, I want to...

  • Check to see within my fourth <tr>, if there is a <td> that has label element with the value of "None".
  • If true, and it's not the last <td>, copy that entire <td> and append it to that <tr> so that its the last <td> in that row.
  • Delete the original <td> that had the value of none.

My HTML in code

<table id="myItems">
<tbody>
<tr>
  <td>...</td>
  <td>...</td>
  <td>...</td>
</tr>
<tr>
  <td>...</td>
  <td>...</td>
  <td>...</td>
</tr>
<tr>
  <td>...</td>
  <td>...</td>
  <td>...</td>
</tr>
<tr>
  <td><input id="item10"><label for="item10">House</label></td>
  <td><input id="item11"><label for="item11">None</label></td>
  <td><input id="item12"><label for="item12">Car</label></td>
</tr>
</table>

What I have tried so far, but needs to be improved....

   //get table name
    const mtarget = 'myItems';

    //check if exists
    if (document.getElementById(mtarget)) {

        //make the swap
        function init() {      
            //if so, target the specific table
            const mtable = document.querySelector("#" + mtarget);
            const lastrow = mtable.querySelectorAll('tbody tr')[3];
            //within it, move the none <td> to the end of existing <tr>
            const tdorgNone = lastrow.querySelectorAll('td')[1];
            const tdcloneNone = tdorgNone.cloneNode(true);
            lastrow.appendChild(tdcloneNone);
            tdorgNone.remove();
        }

        init();

I feel like I'm close, but notice I am not targeting the correct <td> by the label value. I need a deeper understanding of finding the <td> I want by knowing the inner values. How can I improve this code via ECMAScript in 2020?


Solution

  • With a query string, you can pretty concisely select the children of the <tr> you want in an array. Then, you can .find the <td> with the label - if it exists, then just call appendChild on the parent <tr>, and the <td> will be removed from its previous position and put at the bottom.

    const mtarget = 'myItems';
    const tds = [...document.querySelectorAll(`#${mtarget} tr:nth-child(4) td`)];
    const noneTd = tds.find(td => td.children[1].textContent === 'None');
    if (noneTd) {
      noneTd.parentElement.appendChild(noneTd);
    }
    <table id="myItems">
      <tbody>
        <tr>
          <td>...</td>
          <td>...</td>
          <td>...</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
          <td>...</td>
        </tr>
        <tr>
          <td>...</td>
          <td>...</td>
          <td>...</td>
        </tr>
        <tr>
          <td><input id="item10"><label for="item10">House</label></td>
          <td><input id="item11"><label for="item11">None</label></td>
          <td><input id="item12"><label for="item12">Car</label></td>
        </tr>
    </table>