Skip to content Skip to sidebar Skip to footer

Is There A Way To Dynamically Create Nested Divs Onclick?

I'm attempting to create a page where the user is able to customize the form to their needs by adding in extra divs or nested divs (as many layers deep as they'd like). Within each

Solution 1:

Here is a complete solution for you keep in mind that if you need to bind extra events on your produced inputs and buttons you ll have to do it inside the functions addNode or addSub as i did for the click event on the buttons.

Working example : https://jsfiddle.net/r70wqav7/

var counter = 1;
function addNode(element) {
	counter++;
  var new_entry="Entry "+counter+"<br><input type='text' name='myInputs'><br>";
  element.insertAdjacentHTML("beforebegin",new_entry);
}
function addSub(element) {
	counter++;
	var new_sub_entry="<div class='block'>"
  								+"Entry "+counter+"<br><input type='text' name='myInputs'><br>"
                  +"<div class='buttons'>"
                  +"<input class='add_sub_button' type='button' value='add nested'>"
                  +"<input class='add_button' type='button' value='Add another text input' >"
                  +"</div>"
                  +"</div><br />"
                  +"</div>";
  element.insertAdjacentHTML("beforebegin",new_sub_entry); 
  var blocks=element.parentNode.getElementsByClassName("block");
  blocks[blocks.length-1].getElementsByClassName("add_sub_button")[0].addEventListener("click",function(){
  	addSub(this.parentNode);
  });
  blocks[blocks.length-1].getElementsByClassName("add_button")[0].addEventListener("click",function(){
  	addNode(this.parentNode);
  });
}

var buttons=document.getElementsByClassName("add_button");
for(i=0;i<buttons.length;i++){
	buttons[i].addEventListener("click",function(){
  		addNode(this.parentNode);
  });
}
var nested_buttons=document.getElementsByClassName("add_sub_button");
for(i=0;i<buttons.length;i++){
	nested_buttons[i].addEventListener("click",function(){
  		addSub(this.parentNode);
  });
}
div.block{
  padding:5px;
  border:2px solid #000;
}
<form class="form" method="POST">
  <div class="block">
        Entry 1<br><input type="text" name="myInputs"><br>
        <div class="buttons">
          <input class="add_sub_button" type="button" value="add nested">
          <input class="add_button" type="button" value="Add another text input" >
        </div>
  </div><br />
        <input type="submit" value = "answer" multiple="multiple"/>
</form>

EDITED : There was an error binding the click event on nested items updated to work properly


Solution 2:

Here's another worked example which makes use of the concepts I mentioned in an earlier comment. I've moved the Add-Item button outside the form and altered the method used to determine the text for each new item added. Rather than keep a counter, I count the number of existing items in the document and increment it, using this as as the n in the string "Entry n"

I should have added(appended) the sub-item before the button that creates new ones, but was lazy and just called appendChild on the button after the other new element was added - the end result is the same, but it's less efficient and will cause slower performance/shorter battery life.

I was going to use the .cloneNode method of the .dynamicInput div, when clicking "Add new item", however this will copy all subitems of the chosen target and we still need to call addEventListener for the button anyway, so I've opted to simply create each input-item added with the "Add new item" button instead.

<!doctype html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}

window.addEventListener('load', onDocLoaded, false);

function onDocLoaded(evt)
{
    byId('addNewInputBtn').addEventListener('click', myAddNewItem, false);
    var subItemBtn = document.querySelectorAll('.dynamicInput button')[0];
    subItemBtn.addEventListener('click', myAddSubItem, false);
}

function makeNewItem(titleStr)
{
    var div = newEl('div');
    div.className = 'dynamicInput';

    var heading = newEl('h3');
    heading.innerText = titleStr;
    div.appendChild(heading);

    var input = newEl('input');
    div.appendChild(input);

    var btn = newEl('button');
    btn.innerText = 'Add sub-items';
    btn.addEventListener('click', myAddSubItem, false);
    div.appendChild(btn);

    return div;
}


function myAddNewItem(evt)
{
    var numAlreadyExisting = allByClass('dynamicInput').length;             // count number of divs with className = dynamicInput
    var newNum = numAlreadyExisting + 1;
    var newInputPanel = makeNewItem('Entry ' + newNum);
    byId('myForm').appendChild(newInputPanel);
    return false;
}

function myAddSubItem(evt)
{
    evt.preventDefault();                                                   // stops this button causing the form to be submitted
    var clickedBtn = this;
    var inputDiv = clickedBtn.parentNode;
    var newInput = newEl('input');
    inputDiv.appendChild(newInput);
    inputDiv.appendChild(clickedBtn);
}

</script>
</head>
<body>
    <form id='myForm'>
        <div class='dynamicInput'>
         <h3>Entry 1</h3>
         <input type='text'/><button>Add sub-item</button>
        </div>
    </form>
    <button id='addNewInputBtn'>Add new item</button>
</body>
</html>

Post a Comment for "Is There A Way To Dynamically Create Nested Divs Onclick?"