javascripthtmlcssdom-traversal

Target all the label inside a table using javascript


i have the follwing setup. here i am trying to add custom radio and checkboxes.

Array.from(document.querySelectorAll("tr")).forEach((tr,index)=>{
  var mark=document.createElement("span");
  Array.from(tr.querySelectorAll("input")).forEach((inp,index1)=>{
    if(inp.type=="radio"){
      mark.classList.add("dotmark");
      inp.parentNode.appendChild(mark);
    }
    else{
      mark.classList.add("checkmark");
      inp.parentNode.appendChild(mark);//instead append in to the next td's label tag
    }
  })
})
span{
width:20px;
height:20px;
background:#ccc;
display:inline-block;
}
<table id="tab1" class="table labelCustom">
   <tbody>
        <tr><td><input type='radio' id='one' name='name'></td><td><label for='one'>example</label></td></tr>
        <tr><td><input type='radio' id='two' name='name'></td><td><label for='two'>example</label></td></tr>
        <tr><td><input type='radio' id='three' name='name'></td><td><label for='three'>example</label></td></tr>
   </tbody>
</table>

i want the dyanamically created span element to be inserted in the label tag. now it is inserting it in the inputs td.

Note: the class of the span element is depeneding on the input type.


Solution

  • One approach, among many, is the following:

    Array.from(document.querySelectorAll("tr")).forEach((tr, index) => {
      var mark = document.createElement("span");
      Array.from(tr.querySelectorAll("input")).forEach((inp, index1) => {
    
        // caching the <label> element for readability:
        let label = inp.parentNode.nextElementSibling.querySelector('label');
    
        // adding the class-name based on the result of the ternary operator,
        // if the input.type is equal to 'radio' we return the class-name of
        // 'dotmark', otherwise we return 'checkmark':
        mark.classList.add(inp.type === 'radio' ? 'dotmark' : 'checkmark');
    
        // appending the element held within the 'mark' variable:
        label.appendChild(mark);
      })
    })
    span {
      width: 20px;
      height: 20px;
      background: #ccc;
      display: inline-block;
    }
    
    span.dotmark {
      background-color: limegreen;
    }
    
    span.checkmark {
      background-color: #f90;
    }
    <table id="tab1" class="table labelCustom">
      <tbody>
        <tr>
          <td><input type='radio' id='one' name='name'></td>
          <td><label for='one'>example</label></td>
        </tr>
        <tr>
          <td><input type='radio' id='two' name='name'></td>
          <td><label for='two'>example</label></td>
        </tr>
        <tr>
          <td><input type='radio' id='three' name='name'></td>
          <td><label for='three'>example</label></td>
        </tr>
        <tr>
          <td><input type='checkbox' id='four' name='differentName'></td>
          <td><label for='four'>example</label></td>
        </tr>
      </tbody>
    </table>

    As an addendum, from the comment by the OP to the question:

    I tried nextSibling but it does't worked but nextSiblingElement worked.

    The difference between the two is that nextSibling returns any sibling, whether it's a text-node, element-node or any other, whereas nextElementSibling, as the name implies, returns the next sibling which is also an element-node.

    References: