2

I have the following code snippet (Not self written, obtained from Add a list item through javascript)

Demo of relevant Script here: http://jsfiddle.net/Gmyag/

The HTML Portion:

First name:
<input type="text" id="firstname">
<br>
<p>Your first name is: <b id='boldStuff2'></b> 
</p>
<p>Other people's names:</p>
<ol id="demo"></ol>
<input type='button' onclick='changeText2()' value='Submit' />

The JS portion:

var list = document.getElementById('demo');

function changeText2() {
    var firstname = document.getElementById('firstname').value;
    document.getElementById('boldStuff2').innerHTML = firstname;
    var entry = document.createElement('li');
    entry.appendChild(document.createTextNode(firstname));
    list.appendChild(entry);
}

And need to know how one would add a dynamic button that appears next to each entry, say, an "X" mark that once clicked would remove that entry from the array and from the list.

Any and all help is greatly appreciated.

Erick
  • 2,488
  • 6
  • 29
  • 43

2 Answers2

6

Idea is basically giving every name an id and removing them by id on button click.

Updated fiddle

this gives every li an id and adds a button with removeName('itemid') on it's onClick attribute.

entry.setAttribute('id','item'+lastid);
var removeButton = document.createElement('button');
removeButton.appendChild(document.createTextNode("remove"));
removeButton.setAttribute('onClick','removeName("'+'item'+lastid+'")');
entry.appendChild(removeButton);

removeName function simply finds item and remove it from the list.

function removeName(itemid){
    var item = document.getElementById(itemid);
    list.removeChild(item);
}

EDIT: As to why zozo's answer would cause problems: it allows you to add multiple items with same id. I explained in a comment on their answer.

EDIT

So for your 2 requests:

1) Getting data from DOM

Going for this first because it builds up on above answer.

FIDDLE

So we have our names, and able to add and remove them to the list but now we need the data as an array.

added this line for easier access to the name

entry.setAttribute('data-name',firstname);

and getting all names from the list like this:

function getNames(){
    var names = [];
    for(var i=0;i<list.children.length;i++){
        names.push(list.children[i].getAttribute("data-name"));//get previously set attribute and add to array
    }
    return names;
}

We can simply get the attribute we added to get the name. If we do not add that attribute we would have need to go in to the inner nodes of the <li> and grab the text node to get the names. We can't simply get innerText or innerHtml of the li because we added a button( the remove) button inside the li element.

I added another button at the end of the form to test the getNames function.

2) Storing data in js from the begining

So the other approach is different, this time we do not add to/read from DOM but we store everything in an array and. Every time the array changes we render the list for display purposes.

FIDDLE

So, we have a names array that we will add to and remove from.

var names = []; // [] is same as new Array();

We simply add the name to the list and re-render the list

function changeText2() {
    var firstname = document.getElementById('firstname').value;
    document.getElementById('boldStuff2').innerHTML = firstname;
    names.push(firstname);//simply add new name to array;
    //array changed re-render list
    renderList();
}

And when we need to remove we simply remove it from the array and re-render the list:

function removeName(nameindex){
    names.splice(nameindex,1);
    //array changed re-render list
    renderList();
}

As you might guess everything happens in the renderList function:

function renderList(){

we remove everything from the DOM first: According to this answer this is faster than simply doing list.innerHTML = ""

//clean the list
while (list.firstChild) {
    list.removeChild(list.firstChild);
}

Then we create each item again

for(var i=0;i<names.length;i++){
    var entry = document.createElement('li');
    entry.appendChild(document.createTextNode(names[i]));
    var removeButton = document.createElement('button');
    removeButton.appendChild(document.createTextNode("remove"));
    removeButton.setAttribute('onClick','removeName('+i+')');
    entry.appendChild(removeButton);
    list.appendChild(entry);
}

Note that removeName function now takes an array index instead of id. you need to call renderList everytime the array changes so the changes are visible in the dom.

Community
  • 1
  • 1
Quad
  • 1,708
  • 1
  • 10
  • 22
  • In the bottom conversation you also mentioned you could do this with an array. Could you elaborate how you would do that? It would be incredibly helpful to me, since I need to retrieve the data later on. Otherwise just mentioning how to retrieve the data would be incredibly helpful. – Erick May 06 '14 at 22:12
  • I really appreciate it, @Quad – Erick May 06 '14 at 23:00
4

Add this after var = document.createElement('li');

  entry.setAttribute("id", "node" + list.children.length);

This will give your newly created lis ids.

On your remove button add onclick="removeElement(-- here the id of the node you want to remove --)"

And finally add

  function removeElement(id) {
       var element = document.getElementById(id);
       element.parentNode.removeChild(element);
  }
zozo
  • 8,230
  • 19
  • 79
  • 134
  • This allows you to add multiple items with same ids. Add 2 items, length is 2, 2nd item has id of `node1`. Remove first item(node0). list now has 1 item. Add a new one and that will also have `node1` as id because length is 1. – Quad May 06 '14 at 21:39
  • 1
    True, it was a simple fast solution, may need adjusting. For example you can use timestamp instead of list length. Or you can use a lastId as you answered, and make it global. – zozo May 06 '14 at 21:44
  • 1
    Depending on the use case, storing names in a js array instead of DOM and using indices could also be an option. Though that would require removing and adding all items to list every time a change in the js array occurs. (though there are frameworks that do these automagically for us like angularjs and knockout and so on.) – Quad May 06 '14 at 21:58