0

I have this JavaScript function (below) that will dynamically add a new element to the DOM (no problem) except there is no name attribute added or ID value.

The ultimate goal I'm looking to achieve is to be able to dynamically add elements to a process and then be able to save it (submit via jQuery serialize) without a page refresh (in simple terms, think of adding/removing tasks to a project). Dynamically "adding" is what I'm struggling with.

Here is the stripped down code I have so far:

<div id="itemList">
    <div><input class="textInput" name="input_1"  id="input_1" type="text" /></div>
    <div><input class="textInput" name="input_2"  id="input_2" type="text" /></div>
    <div><input class="textInput" name="input_3"  id="input_3" type="text" /></div>
</div>
<div><a href="javascript:void('');" id="addNewInputField" onClick="addNewInputField();">Add New Task</a></div>

<script type="text/javascript">
function addNewInputField(){
    elParentContainer = document.getElementById('itemList');
    newElement = document.createElement('div');
    newInput = document.createElement('input');
    newInput.setAttribute('class', 'textInput');
    newInput.setAttribute('type', 'text');      
    newElement.appendChild(newInput);
    elParentContainer.appendChild(newElement);
}
</script>

and here is the outputted source I'm currently getting when clicking the "Add New Task" twice:

Here is the what I'm currently getting when you view source:

<div id="itemList">
    <div><input class="textInput" name="input_1" id="input_1" type="text"></div>
    <div><input class="textInput" name="input_2" id="input_2" type="text"></div>
    <div><input class="textInput" name="input_3" id="input_3" type="text"></div>
    <div><input class="textInput" type="text"></div>
    <div><input class="textInput" type="text"></div>
</div>

Here is the desired output when you view source:

<div id="itemList">
    <div><input class="textInput" name="input_1" id="input_1" type="text"></div>
    <div><input class="textInput" name="input_2" id="input_2" type="text"></div>
    <div><input class="textInput" name="input_3" id="input_3" type="text"></div>
    <div><input class="textInput" name="input_4" id="input_4" type="text"></div>
    <div><input class="textInput" name="input_5" id="input_5" type="text"></div>
</div>

Can someone help me modify my function to increment the newly added DOM elements?

7 Answers 7

2

You could consider updating your function to see how many current elements there are (via the getElementsByClassName() function) and use that to set your id and name properties respectively when creating your new element :

<script type="text/javascript">
  function addNewInputField(){
      // Set how many elements you have with that class (to determine which
      // value to append to 'input_{x}'
      var currentInput = document.getElementsByClassName('textInput').length + 1;
      elParentContainer = document.getElementById('itemList');
      newElement = document.createElement('div');
      newInput = document.createElement('input');
      newInput.setAttribute('class', 'textInput');
      // Set your new ID attribute
      newInput.setAttribute('id', 'input_' + currentInput);
      // Set your new name attribute
      newInput.setAttribute('name', 'input_' + currentInput); 
      newInput.setAttribute('type', 'text');      
      newElement.appendChild(newInput);
      elParentContainer.appendChild(newElement);
  }
</script>

You can see a working example here and an example of what the output markup would look like below :

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

This solution also worked and answers the question about how to modify the function.
2

Based on your stripped down version, you could keep track of how many inputs you have and update them with each new addition. Here is a solution based on the code you submitted.

   <div id="itemList">
<div><input class="textInput" name="input_1"  id="input_1" type="text" /></div>
<div><input class="textInput" name="input_2"  id="input_2" type="text" /></div>
<div><input class="textInput" name="input_3"  id="input_3" type="text" /></div>

    <div><a href="javascript:void('');" id="addNewInputField" onClick="addNewInputField();">Add New Task</a></div>

    <script type="text/javascript">
     var inputCounter =  3;
     function addNewInputField(){
        var name = "input_";
        inputCounter= inputCounter+1;
        name = name.concat(inputCounter);
        elParentContainer = document.getElementById('itemList');
        newElement = document.createElement('div');
        newInput = document.createElement('input');
        newInput.setAttribute('class', 'textInput');
        newInput.setAttribute('type', 'text');
        newInput.setAttribute('name', name);
        newInput.setAttribute('id', name);      
        newElement.appendChild(newInput);
        elParentContainer.appendChild(newElement);
}
</script>

Comments

1

If you want to use jQuery please consider using code like this:

  var inputCount = $('.textInput').size();
  inputCount += 1;
  $('#itemList').append('<div><input class="textInput" name="input_'+inputCount+'" id="input_'+inputCount+'" type="text" /></div>');

Additionally it may be more appropiate to use the data attribute, you might consider it.

4 Comments

The original question was asking about modify the function but I'm marking this as correct since the solution is so clean. I'd like to see your answer using data-attributes and why you think it'd be more appropriate.
The data attribute is very useful, if you want to save more data than only your IDs. I use it for example, if I am on an edit form. Or you could save a date or complete javascript object in it. Sometimes this comes in very handy. But other times ids and names are sufficient :)
That's a good point. I do also need the parent ID so including it as a data attribute would remove the need to traverse up the DOM to get it. Thanks for the tip!
Implemented your solution and the data-id attribute and it worked beautifully. Just wanted to give you more props for the elegant solution.
1

You can just count how many children your container has and then create dynamically the id and name of the next element.

function addNewInputField(){
elParentContainer = document.getElementById('itemList');
var next_input = elParentContainer.children.length+1
newElement = document.createElement('div');
newInput = document.createElement('input');
newInput.setAttribute('class', 'textInput');
newInput.setAttribute('type', 'text');      
newInput.setAttribute('name', 'input_'+next_input);      
newInput.setAttribute('id', 'input_'+next_input);   
newElement.appendChild(newInput);
elParentContainer.appendChild(newElement);

}

Comments

1

You could keep track of the current number of inputs you have.That way it becomes easier to set the desired attributes of new inputs as you create them.

     <script type="text/javascript">
        var inputCounter =  3;
     function addNewInputField(){
        var name = "input_";
        inputCounter= inputCounter+1;
        name = name.concat(inputCounter);
        elParentContainer = document.getElementById('itemList');
        newElement = document.createElement('div');
        newInput = document.createElement('input');
        newInput.setAttribute('class', 'textInput');
        newInput.setAttribute('type', 'text');
        newInput.setAttribute('name', name);
        newInput.setAttribute('id', name);      
        newElement.appendChild(newInput);
        elParentContainer.appendChild(newElement);
    }

   </script>

1 Comment

This solution also worked and answers the question about how to modify the function.
0

Have you tried Jquery.append() functionality.

Hope this will solve your problem, where you can use to create dynamic elements and also append any text in the page.

Please see the sample and try this link , you will get better idea.

http://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_html_append_ref

Let me know, if any more support needed.

Thanks, Bhuvan

2 Comments

If I not clearly understood your problem statement, please post me what you exactly required.
I'm needing input fields, not just appending text to the the list. But thank you for your contribution.
0

One way to achieve this is to retrieve the last child of the collection, then use one of it's attributes to know the current index. Once this has been retrieved, it's easy to add attributes with the right contents to the newly created element:

function addNewInputField(){
    var elParentContainer = document.getElementById('itemList');

    //Get last child of list
    var inputList = elParentContainer.getElementsByTagName('input');
    var lastChild = inputList[inputList.length-1];

    //Get last index from the name attribute of last child
    var lastIndex = lastChild.getAttribute('name').split('_')[1];

    var newElement = document.createElement('div');
    var newInput = document.createElement('input');
    newInput.setAttribute('class', 'textInput');
    newInput.setAttribute('type', 'text');
    //Add new attributes to the newly created element
    newInput.setAttribute('name', 'input_'+(lastIndex++));
    newInput.setAttribute('id', 'input_'+(lastIndex++));   
    newElement.appendChild(newInput);
    elParentContainer.appendChild(newElement);
}

2 Comments

to whoever -1 this, it would be nice to point out what's wrong with the answer
It wasn't me that -1 your answer but your solution produces an error for me: "Uncaught TypeError: lastChild.getAttribute is not a function"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.