3

I am very new to JavaScript programming and I am trying to learn event handlers in JavaScript. I am adding event handler on dynamically created elements. I made a simple shopping list code by which I am able to enter the data into the list, and i added a delete icon on right of each item.I added event handler on that icon but it works only for item already on list not on the dynamically added ones.

I tried to figure out ways, for around a day but still couldn't figure out the correct way to achieve this with pure JavaScript. I have gone through almost every answer on stack overflow and many other resources, but still couldn't achieve the solution, i took help of one of the answers on stack overflow while figuring out the solution, which is pure JavaScript,

question link: add event listener on elements created dynamically

the question is similar to mine, but i tried as the answer says, but still not working for me.

document.querySelector("ul").addEventListener('click', function(event) {
    if (event.target.tagName === "I") {
        alert("hmm.. you clicked.");
    }
});

fiddle link: https://jsfiddle.net/65erpycb/

var input = document.getElementById("userinput");
var enter = document.getElementById("enter");
var ul = document.querySelector("ul");
var listItem = document.querySelectorAll("li");

function toggleFunction(e) {
    if(e.target.tagName === "LI") {
        e.target.classList.toggle("done");
    }
}

function addListItemOnClick() {
    if (input.value.length > 0) {
        console.log(input.value.length);
        var li = document.createElement("li");
        li.appendChild(document.createTextNode(input.value));
        ul.appendChild(li);
        input.value = "";
        var d = document.createElement("div");
        d.classList.add("fas", "fa-trash");
        li.appendChild(d);
    }
}
function addListItemOnPress() {
    if (input.value.length > 0 && event.keyCode === 13) {
        var li = document.createElement("li");
        li.appendChild(document.createTextNode(input.value));
        ul.appendChild(li);
        input.value = "";
        var d = document.createElement("div");
        d.classList.add("fas", "fa-trash");
        li.appendChild(d);
    }
}
enter.addEventListener("click", addListItemOnClick);
input.addEventListener("keypress", addListItemOnPress);
ul.addEventListener("click",toggleFunction);

document.querySelector("ul").addEventListener('click', function(event) {
    if (event.target.tagName === "I") {
        alert("hmm.. you clicked.");
    }
});
.box {
    text-align: center;
    border: 2px solid black;
}

h1 {
    font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
    font-size: 50px;
}

#first {
    font-size: 25px;
    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
    text-decoration: underline;
}

ul {
    border: 1px solid black;
    padding: 0;
}

li {
    display: block;
    list-style: none;
    font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
    font-size: 15px;
    text-align: center;
    text-decoration: underline;
}

#userinput {
    text-align: center;
}

.done {
    text-decoration: line-through;
}

.fa-trash {
    float: right;
}
<!DOCTYPE html>
<html>
<head>
 <title>Javascript + DOM</title>
 <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
 <div class="box">
 <h1>Shopping List</h1>
 <p id="first">Get it done today</p>
 <input id="userinput" type="text" placeholder="enter items">
 <button id="enter">Enter</button>
 <ul id = "items">
  <li>Notebook<i class="fas fa-trash"></i></li>
  <li>Jello<i class="fas fa-trash"></i></li>
  <li>Spinach<i class="fas fa-trash"></i></li>
  <li>Rice<i class="fas fa-trash"></i></li>
  <li>Birthday Cake<i class="fas fa-trash"></i></li>
  <li>Candles<i class="fas fa-trash"></i></li>
 </ul>
 </div>
 <script type="text/javascript" src="script.js"></script>
 <script src="https://kit.fontawesome.com/28803a998e.js"></script>
</body>
</html>

I am expecting the delete buttons should also work when i add the items dynamically.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
Ayush Mishra
  • 267
  • 3
  • 14
  • I'd encourage you to add the code for the addListItemOnPress function to the question. Linking to the fiddle is a great start, although it does not quite meet the SO definition of a "Complete" question here https://stackoverflow.com/help/minimal-reproducible-example By adding that function implementation, anyone could reproduce the exact problem you described. – Will Jun 07 '19 at 18:39
  • Ah, and addListItemOnClick as mentioned in answer comments. – Will Jun 07 '19 at 18:46

2 Answers2

3

The added items are div tag elements. But the original items are i tag elements. The event.target.tagName === "I" test will only match the i tags, not the div tags.

Update the added items code (in both addListItemOnClick and addListItemOnPress):

document.createElement("div")

to be:

document.createElement("i")
Will
  • 6,601
  • 3
  • 31
  • 42
  • 2
    Ah, you have a couple functions addListItemOnClick and addListItemOnPress. When I change both from `div` to `i`, it works for me. – Will Jun 07 '19 at 18:43
  • @Will Cain, then i should change event.target.tagName === "I" to event.target.tagName.toLowerCase() === "i"; also – Ayush Mishra Jun 07 '19 at 18:44
  • 1
    Uppercase `event.target.tagName === "I"` works for me. See https://stackoverflow.com/questions/27223756/is-element-tagname-always-uppercase or my fiddle above. – Will Jun 07 '19 at 18:46
1

If you separate data and view and use html-inline binding (which is acceptable for small projects - and similar to templates in angular/react/vue frameworks...) the code will be much more small & clean

let data=[
  { name: "Notebook" },
  { name: "Jello" },
  { name: "Spinach" },
  { name: "Rice" },
  { name: "Birthday" },
  { name: "Candles" },
];

function add() {
  data.push({ name: userinput.value });
  userinput.value='';
  refresh();
}

function del(i) {
  data.splice(i,1);
  refresh();
}

function refresh() {
  items.innerHTML = data.map((x,i)=> `
    <li>${x.name}<i class="fas fa-trash" onclick="del(${i})"></i></li>
  `).join('');
}

refresh();
<div class="box">
  <h1>Shopping List</h1>
  <p id="first">Get it done today</p>
  <input id="userinput" type="text" placeholder="enter items">
  <button id="enter" onclick="add()">Enter</button>

  <ul id="items"></ul>

</div>

<script src="https://kit.fontawesome.com/28803a998e.js"></script>
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345