jQuery to Vanilla Js

I used the following code to make a delete function for a Todo List. But how would I write this in plain JS?

$("ul").on("click", "span", function(event){
  $(this).parent().fadeOut(500, function(){
    $(this).remove();
  });
  event.stopPropagation();
});

So there’s a lot going on in there, but it is by and large feasible. The only real part I’m not too familiar with would be handling the fadeOut, but I think the easiest way would be with a CSS animation.

let myEl = document.querySelectorAll("ul");
myEl.map(element => {
  element.addEventListener("click", function(event){
    if (event.target.matches("span") ){
      // Not really sure how you'd handle the fadeOut, probably easiest with a CSS class
     event.target.remove();
    }
  })

something like this I think would work

document.querySelectorAll('ul').forEach(ul => {
  const transition = [{opacity: 1},{opacity: 0}];
  const timing = {duration: 500 };

  ul.addEventListener('click', e => {
    if (e.target.matches('span')) {
      e.currentTarget.animate(transition, timing);
      e.target.remove();
    }
  });
});

What’s the DOM structure though? ie why a span in an unordered list rather than a li item?

1 Like

I’m not very good with jquery, so i might be totally wrong here, but i think the spans are inside an li.

$(this).parent() // $(this) is span and .parent() is the li

1 Like

According to me, it should be like this.

const ul = document.querySelector('ul');
ul.addEventListner('click', function(e) {
    if(e.target.nodeName === "SPAN"){
        e.target.parentElement.addClass(); //Better to be add some CSS classes
    }
    e.stopPropagation();
}

Here’s an alternative solutions.

A few things to note. As @Praveen-coding said its better practice to use classes to trigger animations. So we can use classList.add for this. Also you do not need the <span> tag unless there’s is something specific it’s used for.

Its best to use classes when selecting elements. In the future you may add another UL to this page, this javascript would then cause strange behavior.

How about using somthing like this:

<html>
<head>
  <style>
    .fade {
      opacity: 0;
      transition: 1s linear;
    }

    .remove {
      display: none;
    }
  </style>
</head>
<body>
  <ul>
    <li class="list-item">item 1</li>
    <li class="list-item">item 2</li>
  </ul>
  <script>
    const removeAndFade = (item) =>{
      item.addEventListener('click', e => {
        e.target.classList.add('fade');
        setTimeout(() => {
          e.target.classList.add('remove')
        }, 1000)
      });
    }
    document.querySelectorAll('.list-item').forEach(removeAndFade);
  </script>
</body>
</html>

1 Like

Ah, I get you. I assume for your test, the reason for selecting the span is that in the real thing that would be something like a close button? What @collinstommy says is definitely the best solution I think, mine fades the wrong thing (the list itself rather than the list item), and removes the span rather then the list item. Plus it’s often a lot easier to play around with the animation in CSS, and it’s generally much better for simple stuff like this.

If you want to do the animation in JS (maybe if you want something a bit fancier than just a fade), there are very good libraries available, much better the what is available in jQuery: Greensock is exceptional, and for an excellent lightweight replacement, AnimeJS is also superb.

1 Like

Sure, they are there. But at the moment they do not solve a problem. They are not needed so its easier to remove then.

My post was a response to the question DanCouper asked about the DOM structure.

OP only posted a piece of code, we don’t actually know the DOM structure (we can speculate). I was simply speculating about the structure based on the code in the OP. It wasn’t meant as a solution to anything. Also as the original code posted does use a span, we, or rather he, obviously do need it. And as pointed out, it is possible that the span is a container for something like a delete button.

Also, you can’t attach the event listener to the LI’s (at least not on first load), it is a todo list, the LI’s are not in the DOM until the todo item gets added. You have to attach it to the parent and do event delegation. It is also just best practice to not add event listeners to list items, there can end up being thousands of them for all we know.

1 Like