Incrementing GetElementByID when ID is dynamic

I have a DIV tag that is created by using an onclick event. The DIV tags ID increments itself by 1 every time the button is pressed. Not using a closure just incrementing the ID by adding + i++;

w.id = 'myDiv' + i++;

The DIV is created and increments the ID by 1 every time you click the button. DIV1, DIV2, DIV3.

The issue is that with the way I am incrementing the DIV tag id is that I can’t seem to figure out how to append any child elements to any other DIV besides the first one.

I’ve tried several different ways.

document.getElementById("myDiv").appendChild(y);
document.getElementById("myDiv" + i++).appendChild(y);
document.getElementById("myDiv+1").appendChild(y);
document.getElementById("myDiv"[i]).appendChild(y);

The Div and the child elements are all created but any subsequent child elements are constantly appending themselves to the first DIV only.

I am aware of closures although not as comfortable with Javascript to really implement them.

I will help contribute to the community if anyone can take the time to help out, I know this is my first post.

Hi,

Can you post a runnable demo that demonstrates the problem you are having?

I’m sure it won’t be too hard to figure out :slight_smile:

You need to append each new <div> to your document’s body. Alternatively you can insert it before or after an existing element. I am assuming you do not want to create a <div> within a <div>.

4 Likes

I don’t know if this helps, or is just confusing. I know I struggled with grasping closures the first time.

You can run this in your browser console or snippets. ‘console.dir’ doesn’t appear to work in codepen

function outer() {

    let x = 5
    let y = 10

    function inner() {
        // we only reference 'x' here
        // so cleverly 'y' will not be included
        // in the closure returned with inner
        console.log(x++)
    }

    // return inner along with it's scoped closure (A kind of backpack holding 'x')
    return inner
}

const increment = outer() // inner is returned so the same as const increment = inner
increment() // 6
increment() // 7
increment() // 8

// let's have a peek at increment
console.dir(increment)
// outputs
//  f inner()
//    [[Scopes]][3]
//    0: Closure (outer) {x: 8} <--

// no access to 'x' out here
console.log(x) // ReferenceError: x is not defined

Working off Archibald’s script here is a codepen

just a ps @Archibald
newDIV = document.createElement("DIV"); is defining a global

2 Likes

Here is the snippet. Maybe this will help illustrate the issue. As mentioned before everything works and the DIV tags increments themselves by 1. The issue is appending children to each new DIV tag. Right now the child will append itself to the first DIV but if you click the add Div button more than once the child elements are added to the first DIV again. Below I am using (“myDiv1”) just to show it will append. But that is also the problem I am needing to figure out. How to make (“myDiv1”) dynamic so that with each new button click the myDiv1 changes to myDiv2, myDiv3, etc.

<button onclick="addDiv();">add Div</button>

<script>
var i = 0;
function addDiv() {
var w = document.createElement("DIV");
var z = document.createElement('TEXT');
z.setAttribute("type", "text");
w.id = 'myDiv' + i++;
z.id = 'textDescription';
document.getElementById("Container").appendChild(w);
// how to make myDiv1 change to myDiv2, myDiv3, with each new button click to append children to the last created DIV
document.getElementById("myDiv1").appendChild(z);
}
</script>

You can append it to the appended element.

i.e. document.getElementById("Container").appendChild(w).appendChild(z);

There is no text element in html so I assume you wanted an input element as you were setting its type to text. You would also need to increment the id on the input as well.

Roughly like this but you really should be using an event listener as shown in the demo code from @Archibald.


var i = 0;
function addDiv() {
  var w = document.createElement("DIV");
  var z = document.createElement("INPUT");
  z.setAttribute("type", "text");
  w.id = "myDiv" + i;
  z.id = "textDescription" + i;
  i++;
  document.getElementById("Container").appendChild(w).appendChild(z);
}

If that’s what you wanted then I;'l leave it to the JS gurus here to show you how to tidy that lot up :wink:

You can append it to the appended element.

i.e. document.getElementById("Container").appendChild(w).appendChild(z);

There is no text element in html so I assume you wanted an input element as you were setting its type to text. You would also need to increment the id on the input as well.

Roughly like this but you really should be using an event listener as shown in the demo code from @Archibald.


var i = 0;
function addDiv() {
  var w = document.createElement("DIV");
  var z = document.createElement("INPUT");
  z.setAttribute("type", "text");
  w.id = "myDiv" + i;
  z.id = "textDescription" + i;
  i++;
  document.getElementById("Container").appendChild(w).appendChild(z);
}

If that’s what you wanted then I’ll leave it to the JS gurus here to show you how to tidy that lot up :wink:

Consider using createTextNode() method:

Alternatively, use innerHTML property:

1 Like

I slightly modified the snippet to make it easier.

Thanks for letting me know you can append multiple children to the “Container” but that doesn’t append them to the DIV. There’s a reason I want each DIV to be incremented and for each child to be appended to its corresponding DIV.

The way you are suggesting is to just put everything into the same container and then by doing it that way I can’t accomplish ultimately what I am needing.

Yes it does did you try my example?

It appends the input to the div that you just appended. Although i think its better to do it like this:

If I’ve understood what you meant:)

If that’s not what you meant then post the html of the what you want the finished product to look like so we can work backwards for you.

1 Like

Let me try this. Because your Pen does look like it’s exactly what I am needing.

I tidied it up to get rid of the inline event handler but I’m sure there’s still room for improvement.

So when I append multiple elements using

document.getElementById("Container").appendChild(w).appendChild(x).appendChild(y);

It adds each element inside the element before. So (y) is inside (x) and (x) is inside (w) whereas I am needing (y) and (x) to be inside (w)

There is more than one element that is meant to go inside the DIV. When I append multiple elements, the last element always goes inside the element which was appended directly before

Then do it like this:
e.g.
var z2 = d.createElement("Label");

    w.append(z);
    w.append(z2);
    d.getElementById("Container").appendChild(w);

The whole thing wrapped up.


(function (d) {
  "use strict";
  var i = 0;
  d.querySelector("#addDiv").addEventListener("click", addDiv);
  function addDiv() {
    var w = d.createElement("DIV");
    var z = d.createElement("INPUT");
    var z2 = d.createElement("Label");
    z.setAttribute("type", "text");
    w.id = "myDiv" + i;
    z.id = "textDescription" + i;
    i++;
    w.append(z);
    w.append(z2);
    d.getElementById("Container").appendChild(w);
  }
})(document);

Do it all before you append the whole thing to the DOM only once.

1 Like

To associate a label with an input element either the input element needs to be within the label element (as a child) or the label needs a for attribute attribute whose value is the same as the input’s id

2 Likes

Good point: I was just getting to that )

I’ve amended it here but I’m sure you could tidy that up a lot (the variable names are a mess but I was just following the OPs example).

I’m away for the evening now so I;ll leave you in @Archibald 's capable hands :slight_smile:

@PaulOB @Archibald I truly appreciate everyone’s help! Thank you for welcoming me to the community!

I think everyone probably could create their own solution to the question but I did go with @PaulOB closure solution.

Again, thanks for the input and insights and for taking the time to help!

PS Tried to mention and thank everyone, but I’m a new user and am limited to 2 mentions only.

1 Like