Step 6: removing items

Removing items

The next step will be adding a button to our task item for taking it off of our list.

Let's look at the code of our items:

6.1 — The current markup of each task item

  <li>Buy coffee</li>

Very simple markup; the only thing it contains is the text of the task.

Now we need something like this:

6.2 — The markup we need for adding the remove feature

<li>
  <span>Buy coffee</span>
  <button onclick="removeItem(event)">×</button>
</li>

Here our <li> element contains two children elements: a <span> with some text, and a <button> that we will use to remove the task.

Let’s take a look at how we are currently rendering the task item inside the updateList() function:

6.3 — The code we’re currently using to render the task item element

let element = document.createElement('li');
element.innerHTML = item;
listElement.appendChild(element);

We are doing something very simple to obtain a new task item element; we are creating a new li element, we are giving it some innerHTML, and we are adding it as child to listElement.

As we saw above, now we need something slightly more complex; it's time to move this rendering logic into a new function:

6.4 — A simple renderItem() function

const renderItem = (itemText) => {
  let element = document.createElement('li');
  element.innerHTML = itemText;
  return element;
}

6.5 — Let’s change the code inside updateList() to use the new renderItem() function

listElement.appendChild(renderItem(item));

The end result hasn't change yet, but we have built a dedicated place that will contain all the logic we need for transforming an input (the task item text) to an output (the task item HTML markup).

Now we have some work to do inside the renderItem() function. We have to change our output from what we have now (see 4.1) to what we need (see 4.2). To do this, we will leverage a widely used concept in HTML programming: the templates.

Key concepts: templates and placeholders

A template is a generic piece of HTML code that contains placeholder strings. Replacing placeholder strings with real values is called “compiling a template”.

Let’s create our first template. Inside <body> tag, let’s add this markup:

6.6 — The task item template element

<template id="item-template">
  <li>
    <span></span>
    <button onclick="removeItem(event)">×</button>
  </li>
</template>

We added a <template> element that we are using just for storing some HTML (our template string). This element is not displayed in our page until we explicitly tell the browser to do so. Just think of this element as a “container of text”.

Now let’s go back to our renderItem() function. What we are going to do now is replacing span inner text with our task item text.

6.7 — renderItem() with template

const renderItem = (itemText) => {
  const template = document.querySelector('#item-template');
  let instance = document.importNode(template.content, true);
  instance.querySelector("span").innerText = itemText;
  
  return instance;
}

Cool! Now the markup of each element is changed and a little button is shown next to each of our task items. But if we click on that button, nothing happens. Let’s fix this!

We need to create a removeItem() function (as we wrote in the onclick attribute of our button), that will:

  • remove a task from our list

  • update the task list

To do this, we will use the array's filter() method to update our listItems. Let's take a look at the code

6.8 — the removeItem() function

const removeItem = (event) => {
  const clickedItemText = event.target.previousElementSibling.innerHTML;

  listItems = listItems.filter((item) => clickedItemText != item);

  updateList(listItems);
}

The first thing to notice here is that the removeItem() function does not automatically know which task we want to remove. For JavaScript, what happened is that a button received a click. What happens from now on is completely in our hands.

The way we get to the clicked task text is by accessing the event object, which is generated by the browser each time a user is interacting with an element (eg. clicking on it). In the event object we can find a lot of useful information. For example, the element that received the click (called target: our button).

If we look at the markup, we notice that our button is at the same level of our span, and comes right after it; they are siblings. We want to reach the previous element sibling of the button and read its inner HTML. We do this by calling previousElementSibling on the event.target.

After, we use the filter() method on our listItems array to obtain a new copy of our list that does not contain the task we are removing.

The last step of our removeItem() function will be displaying this new list by calling updateList().

What we just did:

  • we created a template for our task items

  • we added a button on each task item with an onclick attribute

  • we created a function that removes the clicked item by filtering our listItems array

Last updated