简体   繁体   中英

How do I make JS apply to dynamically added DOM elements?

I am dynamically adding new elements to my form, using JavaScript to clone existing elements upon user clicking "add new element" input button. This works well for the first depth level, but I get into problems when I try a second level: I click "add new field", which makes a new set of form fields appear, in addition to a button "Add new subfield". Clicking "Add new subfield" doesn't even call the function it is supposed to call, which is supposed to add new fields within the dynamically added field. From a different project, I remember I was also having trouble with applying JavaScript to new DOM elements, and I think this may be the problem. Is there a way? How?

My code: (js from http://www.quirksmode.org/dom/domform.html )

    <form>
        <span id="writeroot_field"></span>
        <input type="button" id="more_fields" value="Add more fields">
        <input type="submit">
    </form>

    <div id="readroot_field" style="display:none">
        <span id='writeroot_subfield'></span>
        <input type='button' value='Add subfield' id='more_subfields'></input>
        <!-- more fields -->
    </div>

    <div id='readroot_subfield' style='display:none'>
        <!-- form fields -->
    </div>

    <script>
        // main fields
        var counter = 0;
            function moreFields() {
                counter++;
                var newFields = document.getElementById('readroot_field').cloneNode(true);
                newFields.id = '';
                newFields.style.display = 'block';
                var newField = newFields.childNodes;
                for (var i=0;i<newField.length;i++) {
                    var theName = newField[i].name
                    if (theName)
                        newField[i].name = theName + counter;
                }
                var insertHere = document.getElementById('writeroot_field');
                insertHere.parentNode.insertBefore(newFields,insertHere);
            }
        window.onload = moreFields; 
        document.getElementById('more_fields').onclick = moreFields;

        // subfields
        var counter2 = 0;
            function moreSubfields() {
                console.log('entering here? no?');
                counter2++;
                var newFields = document.getElementById('readroot_subfield').cloneNode(true);
                newFields.id = '';
                newFields.style.display = 'block';
                var newField = newFields.childNodes;
                for (var i=0;i<newField.length;i++) {
                    var theName = newField[i].name
                    if (theName)
                        newField[i].name = theName + counter2;
                }
                var insertHere = document.getElementById('writeroot_subfield');
                insertHere.parentNode.insertBefore(newFields,insertHere);
            }

        document.getElementById('more_subfields').onclick = moreSubfields;
    </script>

When using cloneNode() event handlers that have been set like

element.onclick = function() { ... }

or

element.addEventListener("click", function() { ... })

will not be cloned (see MDN: Node.cloneNode ).

The solution to your problem is to set an event handler to the new node on each duplication:

<form>
    <span id="writeroot_field"></span>
    <input type="button" id="more_fields" value="Add more fields">
    <input type="submit">
</form>

<div id="readroot_field" style="display:none">
    <span id='writeroot_subfield'></span>
    <input type='button' value='Add subfield' id='more_subfields'></input>
    <!-- more fields -->
</div>

<div id='readroot_subfield' style='display:none'>
    <!-- form fields -->
</div>

<script>
    // main fields
    var counter = 0;
        function moreFields() {
            counter++;
            var newFields = document.getElementById('readroot_field').cloneNode(true);
            newFields.id = '';
            newFields.style.display = 'block';
            //set event handler
            newFields.onclick = moreFields;
            var newField = newFields.childNodes;
            for (var i=0;i<newField.length;i++) {
                var theName = newField[i].name
                if (theName)
                    newField[i].name = theName + counter;
            }
            var insertHere = document.getElementById('writeroot_field');
            insertHere.parentNode.insertBefore(newFields,insertHere);
        }
    window.onload = moreFields; 
    document.getElementById('more_fields').onclick = moreFields;

    // subfields
    var counter2 = 0;
        function moreSubfields() {
            console.log('entering here? no?');
            counter2++;
            var newFields = document.getElementById('readroot_subfield').cloneNode(true);
            newFields.id = '';
            newFields.style.display = 'block';
            //set event handler
            newFields.onclick = moreSubfields;
            var newField = newFields.childNodes;
            for (var i=0;i<newField.length;i++) {
                var theName = newField[i].name
                if (theName)
                    newField[i].name = theName + counter2;
            }
            var insertHere = document.getElementById('writeroot_subfield');
            insertHere.parentNode.insertBefore(newFields,insertHere);
        }

    document.getElementById('more_subfields').onclick = moreSubfields;
</script>

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