0

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>
user3582590
  • 177
  • 2
  • 4
  • 13
  • just make click event for body like `$('body').on('click','#more_subfields', function() { etc })` – Michael Jul 29 '14 at 08:56
  • If you want dynamically added elements to have listeners, then you need to add listeners. You can do that dynamically, add listeners in–line and clone the elements, or use event delegation. Your choice. – RobG Jul 29 '14 at 09:01
  • @Barmar—I don't agree that the answer is necessarily event delegation. That is one solution, not necessarily **the** solution and isn't mentioned in the question. – RobG Jul 29 '14 at 09:04
  • @Michael He's not using jQuery. – Barmar Jul 29 '14 at 09:19
  • @RobG OK, I've reopened the question. It seems like this has probably come up before, so there should be a better question to make it a duplicate of. – Barmar Jul 29 '14 at 09:20

1 Answers1

0

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>
chm-software.com
  • 351
  • 2
  • 10