简体   繁体   中英

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 div I'd like to have text input and a button which adds another div on the same level and a button that nests a div within it. Both divs should again have a text input and a button which does the same thing.

However I've gotten a bit stuck. When I attempt to create a nested div I always end up adding it at the very bottom instead of inside its parent.

<html>
    <script type="text/javascript">
        var counter = 1;
        function addNode() {
            var newDiv = document.createElement('div');
            counter++;
            newDiv.innerHTML = "Entry " + counter + " <br><input type='text' name='myInputs'>";
            document.getElementById("dynamicInput").appendChild(newDiv);
            var newButton = document.createElement('button');
            newButton.type = "button";
            newButton.onclick = addSub;

            document.getElementById("dynamicInput").appendChild(newButton);
        }
        function addSub() {
            var newDiv = document.createElement('div');
            counter++;
            newDiv.innerHTML = "Entry " + counter + " <br><input type='text' name='myInputs' style='margin:10px'>";
            document.getElementById("subInput").appendChild(newDiv);
        }
    </script>
    <form class="form" method="POST">
        <div id="dynamicInput" name="dynamicInput" multiple="multiple">
            Entry 1<br><input type="text" name="myInputs">
            <div id="subInput" name="subInput" multiple="multiple">
                <input type="button" value="add nested" onClick="addSub();">
            </div>
        </div>
        <input type="button" value="Add another text input" onClick="addNode();" >
        <input type="submit" value = "answer" multiple="multiple"/>

    </form>
</html>

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

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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM