Search code examples
javascriptappendchild

JS Append child to each element of class


function makeCategory() {
    getList = document.getElementById("list");
    cat = document.createElement("div");
    cat.setAttribute("class", "cat");
    getList.appendChild(cat);
    cat.innerHTML =
        '<input type="text" name="name"/><span class="removeButton" onclick= "remove(this)">-</span><br><span class="makeSubCat" onclick="makeSubCategory(this)">+Category</span>';
}

function remove(z) {
    document.getElementById("list").removeChild(z.parentNode);
}

function makeSubCategory(i) {
    y = document.createElement("input");
    x = document.getElementsByClassName("cat");
    x[i].appendChild(y);
}

Can't figure out how i can append child on each element of the class with "onclick". It's not working with "for loop" - it's always appends to the latest div. It's only works when i specify the number of class element.


Solution

  • Demo Outline

    • Reworked the HTML tags into a real Description List or <dl>
    • Instead of trying to manipulate multiple elements recursively, we will drive the functions by the click event
    • Use of Event Delegation saves us a ton of extra code. Only one eventListener() is needed for an unlimited number of <button>s and <input>s.
    • Template Literal was used in lieu of string literal
    • insertAdjacentHTML() played an important part of the add() function

    Details are commented within the demo

    Demo

    // Reference the Description List dl#list
    var dock = document.getElementById("list");
    
    /* Callback function
    || if the clicked button is NOT dl#list...
    || - tgt/e.target is the clicked <button>
    || - if tgt has .add, then call add()...
    || else if tgt has .rem...
    || cat is its parent (.cat)
    || - Get div.cat parent and remove .cat
    */
    function mod(e, dock) {
      if (e.target !== e.currentTarget) {
        var tgt = e.target;
        if (tgt.className === 'add') {
          add.call(this, dock);
        } else if (tgt.className === 'rem') {
          var cat = tgt.parentNode;
          cat.parentNode.removeChild(cat);
        } else return;
      }
    }
    
    /* Register the ancestor of all of the .cat
    || and <button>s. (dl#list).
    || By doing this there's no need to addEventListeners
    || for every <button>
    */
    dock.addEventListener('click', function(e) {
      mod(e, this);
    }, false);
    
    /* This function expression takes a string (in this
    || case the string is a Template Literal.) and
    || parses it into HTML as it inserts it at a 
    || position determined by the first parameter:
    || "beforeend" 
    || (exactly like append)
    */
    var add = function(dock) {
      var cat = `<dd class='cat'>
                  <input name="name" type='text'>
                  <button class="rem">-</button>
                  <button class="add">+</button>
                 </dd>`;
      dock.insertAdjacentHTML('beforeend', cat);
    };
    #list {
      margin: 20px;
      border: 2px ridge gold;
      background: rgba(0, 0, 0, .3);
      padding: 5px 10px 15px;
    }
    
    dt {
      font: 700 20px/1 Consolas;
      color: gold;
      background: rgba(0, 0, 0, .5);
      padding: 5px;
    }
    
    dd {
      font-size: 16px;
      color: #fff;
      background: rgba(0, 0, 0, .5);
      padding: 5px;
      margin: 8px 4px 8px 0;
    }
    
    input,
    button {
      width: 10%;
      font: inherit;
      display: inline-block;
    }
    
    input[type='text'] {
      width: 76%;
    }
    <dl id='list'>
    
      <dt>Category List</dt>
    
      <dd class='cat'>
        <input name="name" type='text'>
        <button class="add">+</button>
      </dd>
    
    </dl>