skip to Main Content

I am trying to learn stuff I was used to doing in jQuery in plain JavaScript.

I have an example I found on the internet to solve, which gave me a hard time.

I am trying to remove the parent div. single on click on the button. remove.

Here is the code;

<div class="row" id="showAward">

</div>
<div class="w-100 text-center">
    <a id="add" class="bg-primary text-white px-3 py-2 rounded-circle cursor-pointer">
        <i class="fa-solid fa-plus"></i>
    </a>
</div>

<script>
    let count = 0;

    document.addEventListener('click', function(event) {
        if (event.target.id === 'add') {
            count++;
            addAward(count);
        }
        if (event.target.classList.contains('delete')) {
            event.currentTarget.parentNode.remove();
        }
    });
    function addAward(number) {
        let html = `<div class="col-lg-4 mb-3 position-relative">
            <label for="image${number}" class="form-label">image ${number}</label>
            <input type="file" class="form-control" id="image${number}" name="image${number}">
            <a class="delete text-danger cursor-pointer position-absolute end-0 top-0"><i class="fa-solid fa-times"></i></a>
        </div>`;
        document.getElementById('showAward').insertAdjacentHTML('beforeend', html);
    }

</script>

2

Answers


  1. It looks like, when the event listener is on document the property curretnTarget is undefined. Use event.target instead. And then instead of using parentNode use the method closest(). You can give a CSS selector as a parameter to the method and get a parent element.

    let count = 0;
    
    document.addEventListener('click', function(event) {
      if (event.target.id === 'add') {
        count++;
        addAward(count);
      }
      if (event.target.classList.contains('delete')) {
        event.target.closest('div.position-relative').remove();
      }
    });
    
    function addAward(number) {
      let html = `<div class="col-lg-4 mb-3 position-relative">
                <label for="image${number}" class="form-label">image ${number}</label>
                <input type="file" class="form-control" id="image${number}" name="image${number}">
                <a class="delete text-danger cursor-pointer position-absolute end-0 top-0"><i class="fa-solid fa-times"></i>Delete</a>
            </div>`;
      document.getElementById('showAward').insertAdjacentHTML('beforeend', html);
    }
    <div class="row" id="showAward">
    
    </div>
    <div class="w-100 text-center">
      <a id="add" class="bg-primary text-white px-3 py-2 rounded-circle cursor-pointer">
        <i class="fa-solid fa-plus"></i>Add
      </a>
    </div>
    Login or Signup to reply.
  2. Event‘s currentTarget getter will return the EventTarget in the bubbling chain where the event is being dispatched at the current phase.
    It will change dynamically and when gotten synchronously from a callback to EventTarget.addEventListener(), it will be the EventTarget on which you called addEventListener() (which makes it similar to this in this regard).

    const parent = document.querySelector(".parent");
    const child = document.querySelector(".child");
    
    const initialEvent = new Event("foobar", { bubbles: true });
    
    let childEvent = null;
    child.addEventListener("foobar", (evt) => {
      console.log("#### In child");
      childEvent = evt; // Store for later
      // It's actually the same object that is passed along
      console.log("initialEvent === evt", initialEvent === evt);
      console.log("evt.currentTarget", evt.currentTarget); // .child
      setTimeout(() => {
        console.log("#### In timeout from child");
        // currentTarget becomes null after the dispatch is done
        console.log("evt.currentTarget", evt.currentTarget);
      });
    });
    parent.addEventListener("foobar", (evt) => {
      console.log("#### In parent");
      // Still the same object
      console.log("initialEvent === evt", initialEvent === evt);
      console.log("evt.currentTarget", evt.currentTarget); // .parent
      console.log("childEvent.currentTarget", childEvent.currentTarget); // .parent
    });
    
    child.dispatchEvent(initialEvent);
    console.log("#### After dispatch");
    console.log("childEvent.currentTarget", childEvent.currentTarget); // null
    <div class="parent"><div class="child"></div></div>

    So in your case currentTarget in that context would the the Document node, because you did call document.addEventListener().

    Now, .target would represent the EventTarget on which the event has been dispatched, i.e. in case of a click, the element that did receive the click.
    However, it may not be the one you were expecting. For instance in you case, clicking the <i> element that is inside the .delete one, would set the .target to that <i> element, and not to the .delete one and thus you’d miss the click.

    Instead when delegating use .closest() to test if the element you’re actually interested in is in the event chain. This method also returns the element in which it’s been called in case it matches.

    document.addEventListener("click", (evt) => {
      console.log("target", evt.target);
      console.log("target is .delete", evt.target.classList.contains("delete"));
      const actualTarget = evt.target.closest(".delete");
      console.log("actualTarget", actualTarget);
    });
    <span class="delete">
      <i>click me</i>
    </span>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search