How to Dynamically Generate Unique ID's for DOM Elements
Tags: html, javascript, programming
Published: 2023-11-16 17:11:07

Let's say you're hiring a new developer, and you've got a simple form setup on your site for them to enter their information. Name, Age, etc. are all pretty straightforward. 

Experience is a little uncertain, since some people may be fresh graduates and others may be industry veterans. You decide to just provide 3 spaces on your form for their most recent, assuming that even graduates can fill that much with their pre-industry work.
But when you get along to skills, you hit a hurdle. Even a basic tech stack tends to have five or more working parts to it, and people with plenty of experience can be functionally proficient in dozens of technologies. Do you populate your form with dozens of fields? Just ask for the 5 most relevant? In a strictly-defined form, no answer feels like the "correct" one. If only you could let the user decide how many skills they wanted to include.

Well luckily, you can!

The most direct implementation is as follows. We have a simple "+" button in the code below, and the goal is to have another field added to the skill section when it's clicked. 

```html
<form id="employee-form">
//
//
//              Previous form info
//              Name, age, etc.
//
//
<div id="skills-section">
<input type="text" class="skill">Skill goes here</input>
<input type="text" class="skill">Skill goes here</input>
<button id="skill-add-button" type="btn">+</button>
</div>
//...
//...</form>

```

Let's head over to our JS. Since we want to add functionality to a button, we'll use a query selector to access it from our code, and then add an event listener to it. In this case, we'll be using a "click" event. 

```js
document.querySelector("#skill-add-button").addEventListener("click", ()=>{
      const skillDiv = document.querySelector("#skills-section")

})
```

So now we have our button setup to do *something* when it gets clicked, but we're not actually telling it what we want. For our purposes, we're going to again use a query selector to select the parent div that holds all of our skills.
Next, we'll create the new field using the createElement method. Once it's been declared as a variable, we can add the attributes the other inputs on our form have. Following that, we can append it to the div we selected earlier, making it appear on our page when the button is clicked


```js
document.querySelector("#skill-add-button").addEventListener("click", ()=>{
      const skillDiv = document.querySelector("#skills-section")
      const newSkill = document.createElement("input")
      newSkill.classlist = "skill"
      newskill.type = "text"
      skillDiv.append(newSkill)
      
})
```
And with that, we've added more elements to our form, and any potential candidates can add as many skills as they want!

But let's say that in parsing our data, we've found that only some of the skills are relevant to what we're hiring for. Specifically every third skill. So to save us time, when our form is submitted, we only care about saving the useful skills. How do we implement that using vanilla javascript? Well, for starters, we'll need a better way to identify our inputs. Lets add some ids to our hardcoded inputs. Since our eventual goal is to find every 3rd input, we'll use incrementing numbers in their ids

```html
<div id="skills-section">
<input type="text" id="skill-1" class="skill">Skill goes here</input>
<input type="text" id="skill-2" class="skill">Skill goes here</input>
<button id="skill-add-button" type="btn">+</button>
</div>
```
Now comes the tricky part. How do we keep the user-generated skills appropriately id'ed so we can sort them later? Here is one simple implementation. Inside of our click event:


```js
document.querySelector("#skill-add-button").addEventListener("click", ()=>{
      const skillDiv = document.querySelector("#skills-section")
      const newSkill = document.createElement("input")
      newSkill.classlist = "skill"
      newSkill.type = "text"
      newSkill.id=`skill-${skillCount}
      skillDiv.append(newSkill)
      
})
```

String interpolation is very useful here, but your immediate thought is probably "but where are we getting stringCount from?" The answer is simple: we haven't yet! But we're about to. Any time this click event fires, our code needs to know how many skills already exist, so it can appropriately number the new skill. Luckily, there's a method for that readily available. querySelectorAll. This method will return a NodeList containing all of the DOM elements that match the parameter passed in. In our case, we want everything with the class "skill". More importantly, we want to know how many elements there are with that class, so we can specifically ask for the length of that NodeList by adding .length to the end of the query.

We just need to add a +1 in the interpolator to make sure our new id isn't conflicting with the skill ahead of it.

```js
document.querySelector("#skill-add-button").addEventListener("click", ()=>{
      const skillDiv = document.querySelector("#skills-section")
      const newSkill = document.createElement("input")
      const skillCount = document.querySelectorAll(".skill").length
      newSkill.classlist = "skill"
      newSkill.type = "text"
      newSkill.id=`skill-${skillCount+1}
      skillDiv.append(newSkill)
      
})
```


Now, when we submit our form, we have full control over which specific skill we want to get a hold of. Whether it's every third, odds only, or one specific skill somewhere in the middle, everything has it own unique id, generated on-the-fly!