Event delegation doesn't work so well

Hello everyone,
I’m practicing event delegation. I create a list and assign(is this a correct word for in my context) event handler to its parent (which is < ul>tag), when you click on one of its child element, that one will be removed by removed() method and print out some information about the list.
It works just fine until I click on the gap between(or on the x-axis) the elements. All of the child elements disappear without being touched. Sometimes the console in devtools will tell me about the error but sometimes it doesn’t and I even don’t understand what it shows to me.
I also tried to use event.stopPropagation() (in case it bubbling up) but it didn’t work.
Please have a look at my code below. Thank you!

<!DOCTYPE html>
<html lang="en">
<head>
	<title>Document</title>
	<style>
		a {
			text-decoration: none;
			display: block;
			background-color: aqua;
			width: 100px;
			text-align: center;
			line-height: 1.5em;
			border: 1px solid black;
			margin: 10px;
		}
		a:hover {
			background-color: blueviolet;
			color:chartreuse;
		}
		li {
			display: inline-block;
			list-style-type: none;
		}
	</style>
</head>
<body>
	
	<ul id="main"
		><li><a href="">one</a></li
		><li><a href="">two</a></li
		><li><a href="">three</a></li
		><li><a href="">four</a></li
		><li><a href="">five</a></li
	></ul>


	<script>
		const main = document.getElementById("main")

		function removeItem(event) {
			event.preventDefault();
			//event.stopPropagation();
			const targetedItem = event.target.parentNode;
			targetedItem.remove();
			console.log("(-_-) (-_-) (-_-) (-_-) (-_-)");
			console.log(`${targetedItem.textContent} has been removed. \n${main.childNodes.length} item(s) left.`);
		}
		main.addEventListener("click", removeItem);
	</script>
</body>
</html>

When you click between the items you are hitting a <li> instead of an <a> and then you are deleting the parent of that li which is the ul

1 Like

The issue is with this line:

const targetedItem = event.target.parentNode;

If you click somewhere between the <li>, the parentNode that gets removed is the <ul>. If you’re clicking on the <ul> and don’t hit a <li>, and the parentNode of the <ul> is the <body>. So you first want to check if you clicked on a <li>, and only then remove it.

1 Like

To encompass it all, in between the a tags you are hitting an li, but if you click beside the li, but on the outside you are hitting the ul itself

1 Like

Thank you for helping me understand the problem!
I will find a solution for this.

<style>
		a {
			text-decoration: none;
			display: block;
			background-color: aqua;
			width: 100px;
			text-align: center;
			line-height: 1.5em;
			border: 1px solid black;
			margin: 10px;
		}
		a:hover {
			background-color: blueviolet;
			color:chartreuse;
		}
		li {
			display: inline-block;
			list-style-type: none;
		}
	</style>
</head>
<body>
	
	<ul id="main"
		><li><a href="">one</a></li
		><li><a href="">two</a></li
		><li><a href="">three</a></li
		><li><a href="">four</a></li
		><li><a href="">five</a></li
	></ul>


	<script>
		const main = document.getElementById("main")

		function removeItem(event) {
			 event.preventDefault();
			 
			 const targetedItem =              event.target;

    if (targetedItem.nodeName === 'A') {
			targetedItem.remove();
			//console.log("(-_-) (-_-) (-_-) (-_-) (-_-)");
			
      console.log(`${targetedItem.innerText} has been removed. \n${main.childNodes.length} item(s) left.`); 
		} 
    }
		main.addEventListener("click", removeItem);
	</script>
</body>
</html>

with some very slight changes this makes it work.

Thank you for your help, @caryaharper !
Your solution is great! But I realize that targetedItem.remove() only removes <a> tag but not the<li> tag which will leave some strange blank space on the browser after removing the <a> tag.
In other words, <ul> tag still have 5 child elements ( empty <li> tags ) even when we have nothing to show on the browser.
so here is my new code now:

	<ul id="main"
		><li><a href="#">one</a></li
		><li><a href="#">two</a></li
		><li><a href="#">three</a></li
		><li><a href="#">four</a></li
		><li><a href="#">five</a></li
	></ul>



	<script>
		const main = document.getElementById("main");
		function removeItem() {
			const targetedItem = event.target;
			if ( targetedItem.nodeName == "A" ) {
				targetedItem.parentNode.remove();
			}
		}
		main.addEventListener("click", removeItem);
	</script>

I place “#” sign into href attribute of <a> so I remove event.preventDefault() from my code.
I’m trying to rewrite this function with forEach() or map(), if it’s possible, perhaps.