skip to Main Content

I know there are a lot of answers to dynamically adding/removing inputs, but I haven’t seen anything about shifting the IDs. I want to dynamically add/remove inputs with Javascript. The inputs must all have unique IDs, and if the input is removed, all the IDs must shift in place to a 1,2,3 format.

For instance, if I have:
1 = Bread
2 = Milk
3 = Cheese

And I want to remove Milk and add Apples, I should get:
1 = Bread
2 = Cheese
3 = Apples

I have tried a couple approaches, but I’m still stuck. Unfortunately, the ids are getting duplicated, and they aren’t shifting as I’d hoped. This is what I’m getting:
1 = Bread
3 = Cheese
3 = Apples

The first approach I tried was just id++ and id–, but obviously that doesn’t work because it doesn’t take into account existing ids. The next approach was putting everything into an array, then making id = index, but I seem to be having the same problem, and I’m not quite sure where to go from here.

let id = 0;
let groceryList = document.getElementById("groceryList");
var groceryItems = [];

/*Make it easier to add lots of attrs*/
function setAttributes(el, attrs){
     for(var key in attrs) {
          el.setAttribute(key, attrs[key]);
     }
}

function addItem(){
let itemId = "item" + id;

/*Create Fieldset*/
var groceryItem = document.createElement("fieldset");
groceryItem.id = itemId;

/*Create Label*/
var inputLabel = document.createElement("label");
var labelText = document.createTextNode("Item " + id);
inputLabel.appendChild(labelText);
inputLabel.setAttribute("for", "text" + itemId);
groceryItem.appendChild(inputLabel);

/*Create Text Input*/
var textInput = document.createElement("input");
textInput.setAttribute("type", "text");
textInput.style = "display:block";
textInput.id = "text" + itemId;
groceryItem.append(textInput);

/*Create Number Label*/
var numberLabel = document.createElement("label");
var numberlabelText = document.createTextNode("Amount");
numberLabel.appendChild(numberlabelText);
numberLabel.setAttribute("for", "num" + itemId);
groceryItem.appendChild(numberLabel);

/*Create Number Input*/
var numInput = document.createElement("input");
setAttributes(numInput, {"type": "number", "min": "0", "max": "100", "value": "1"});
numInput.style = "display:block";
numInput.id = "num" + itemId;
groceryItem.append(numInput);

/*Remove Grocery Item Button*/
var removeItem = document.createElement("button");
var removeItemText = document.createTextNode("Remove " + itemId);
removeItem.appendChild(removeItemText);
removeItem.id = "remove" + itemId;
removeItem.setAttribute("type","button");
removeItem.setAttribute("onclick","remove(this.parentElement)");
groceryItem.append(removeItem);

/*Add all to form*/
groceryItems.push(groceryItem.innerHTML);
updateIDs();
let lastInArr = groceryItems.slice(-1);
var addField = document.createElement('fieldset');
addField.innerHTML = lastInArr;
groceryList.append(addField);
}

/*?????????????*/
/*Trouble Areas*/
/*?????????????*/
function remove(el){
     groceryItems.splice(el,1);
     groceryList.removeChild(el);
     updateIDs();
}

function updateIDs(){
     id=0;
     for(let i = 0; i < groceryItems.length; i++){
          id = i+1;
     }
     console.log(groceryItems);
}

Here’s my codepen.
I apologize if my code is atrocious.

NOTE This example is a simplified version of a larger goal, where I would need IDs (or some type of unique identifier) to pair labels with inputs, link inputs with range sliders, get values, display combined values, etc. From what I’ve been reading, a lot of solutions stray away from the ID approach, but I would still need to use (easily accessible) unique identifiers for the project.

Also, I would prefer pure js, but I can use jQuery if need be.

2

Answers


  1. I would suggest that if you’re associating items to specific IDs, those IDs should remain attached to those items. Once you start reassigning IDs it gets a bit difficult to keep track of. If this where a scenario where you were reading records from a database and each record has a unique ID, if you deleted one of those records, the remaining records should not be reassigned their ID. Otherwise, you’ll run into a situation where you’re not able to find the record you were looking for, or, I suppose a situation that you’re currently involved in.

    If you want to keep things ordered visually, using a simple counter like how you’re doing is fine but I would stay away from reassigning IDs to particular items.

    Login or Signup to reply.
  2. You need to change your remove function you need to get element to update their id
    Here is the javascript code

    let id = 0;
    let groceryList = document.getElementById("groceryList");
    var groceryItems = [];
    /*Make it easier to add lots of attrs*/
    function setAttributes(el, attrs) {
      for (var key in attrs) {
        el.setAttribute(key, attrs[key]);
      }
    }
    
    function addItem() {
      let itemId = "item" + id;
      /*Create Fieldset*/
      var groceryItem = document.createElement("fieldset");
      groceryItem.id = itemId;
      /*Create Label*/
      var inputLabel = document.createElement("label");
      var labelText = document.createTextNode("Item " + id);
      inputLabel.appendChild(labelText);
      inputLabel.setAttribute("for", "text" + itemId);
      groceryItem.appendChild(inputLabel);
      /*Create Text Input*/
      var textInput = document.createElement("input");
      textInput.setAttribute("type", "text");
      textInput.style = "display:block";
      textInput.id = "text" + itemId;
      groceryItem.append(textInput);
      /*Create Number Label*/
      var numberLabel = document.createElement("label");
      var numberlabelText = document.createTextNode("Amount");
      numberLabel.appendChild(numberlabelText);
      numberLabel.setAttribute("for", "num" + itemId);
      groceryItem.appendChild(numberLabel);
      /*Create Number Input*/
      var numInput = document.createElement("input");
      setAttributes(numInput, { type: "number", min: "0", max: "100", value: "1" });
      numInput.style = "display:block";
      numInput.id = "num" + itemId;
      groceryItem.append(numInput);
      /*Remove Grocery Item Button*/
      var removeItem = document.createElement("button");
      var removeItemText = document.createTextNode("Remove " + itemId);
      removeItem.appendChild(removeItemText);
      removeItem.id = "remove" + itemId;
      removeItem.setAttribute("type", "button");
      removeItem.setAttribute("onclick", "remove(this.parentElement)");
      groceryItem.append(removeItem);
      /*Add all to form*/
      groceryItems.push(groceryItem.innerHTML);
      updateIDs();
      let lastInArr = groceryItems.slice(-1);
      var addField = document.createElement("fieldset");
      addField.innerHTML = lastInArr;
      groceryList.append(addField);
    }
    /*?????????????*/
    /*Trouble Areas*/
    /*?????????????*/
    function remove(el) {
      groceryItems.splice(el, 1);
      groceryList.removeChild(el);
      let element = document.querySelectorAll('fieldset');
      let id = 0;
      element.forEach(item => {
        let newid = id++;
        item.querySelector('input').id = newid;
        item.querySelector('label').textContent = 'Item'+ ' ' + newid;
        item.querySelector('button').textContent = 'Remove item'+ ' ' + newid;
        console.log(item);
      })
      updateIDs();
    }
    function updateIDs() {
      id = 0;
      for (let i = 0; i < groceryItems.length; i++) {
        id = i + 1;
      }
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search