The question is published on by Tutorial Guruji team.
I am having some difficulty using parentNode.removeChild()
. I have a list of ‘items’ in an un-ordered list, each have there own delete button. I am trying bind a click event to each individual button that will delete it’s respective parent ‘item’.
My code so far:
<ul class="list"> <h2>This is a list</h2> <li class="item"> <h3>Some Item</h3> <button class="delete">Delete</div> </li> <li class="item"> <h3>Some Item</h3> <button class="delete">Delete</div> </li> <li class="item"> <h3>Some Item</h3> <button class="delete">Delete</div> </li> </ul> var childElements = document.getElementsByClassName('item'); var buttonElement = document.getElementsByClassName('delete'); function deleteItem(buttonsClass, childClass) { for (var i=0;i<buttonsClass.length;i++) { var child = childClass[i]; buttonsClass[i].addEventListener('click', function(child) { childClass[i].parentNode.removeChild(childClass[i]); }, false); } } deleteItem(buttonElement, childElements);
I know there is an easier way to do this with jQuery but i really want to solve this with plain javascript. Thank you for any and all help.
Answer
This is a perfect case for event delegation. No need for jQuery at all:
(function(window, htmlElement) { 'use strict'; htmlElement.addEventListener("click", handleClick, false); function handleClick(event) { if (event.target.classList.contains("delete")) { event.preventDefault(); removeItem(event.target); } } function removeItem(button) { var item = getItem(button), confirmMessage; if (item) { confirmMessage = item.getAttribute("data-confirm"); if (!confirmMessage || window.confirm(confirmMessage)) { item.parentNode.removeChild(item); } } else { throw new Error("No item found"); } } function getItem(button) { var element = button.parentNode, item = null; while (element) { if (element.nodeName === "LI" || element.nodeName === "TR") { item = element; break; } element = element.parentNode; } return item; } })(this, this.document.documentElement);
You have one click handler for the entire page, regardless of how many delete buttons you have. This should also work for list items or table rows, and by specifying a data-confirm
attribute on your buttons, it will pop up a confirm box before removing it.
<button type="button" class="delete" data-confirm="Are you sure you want to delete this item?"> Delete </button>
You can also easily change this so it uses another attribute to find the delete button:
<button type="button" class="delete" data-delete data-confirm="..."> Delete </button>
Just change the condition of the if
statement in the handleClick function to:
if (event.target.hasAttribute("data-delete")) { event.preventDefault(); removeItem(event.target); }
This decouples your behavior from styling. You can use the delete
class name for styling, and the data-delete
attribute for JavaScript behavior. If you need to change the name of the CSS delete class for any reason, or use a different class, because you decide to use a third party CSS framework like Bootstrap, then you don’t need to change a single line of JavaScript.
The last advantage here is that the click handler is attached to the document.documentElement
object, which is available the moment JavaScript begins executing and represents the <html>
element. No need for jQuery’s document ready event handler. Just attach the click handler and import the script at any point on the page.