Lesson 4
Reordering Todo Items
Lesson Overview

In this lesson, we will explore how to dynamically reorder items in a to-do list using JavaScript. We will cover the following topics:

  1. Understanding the children property: Learn how to access child elements of a parent list (HTML ul tag).
  2. Converting HTML Collections into Arrays: Convert HTMLCollections into JavaScript arrays to leverage array methods.
  3. Finding the Index of a List Item: Use the indexOf method on arrays to find the position of a list item.
  4. Using the insertBefore function: Learn how to move items within a list using the insertBefore method.
  5. Combining Concepts: Reordering with Buttons: Implement buttons to move items up and down within the list.
Understanding the children property

Every HTML element on a web page is part of the Document Object Model (DOM), which means it can be thought of as an object. These objects can have child objects as well. So, if we have a simple <ul> HTML tag with several <li> tags inside, we can say that the <ul> tag is the parent, and the <li> tags are its children.

As we're dealing with a dynamic to-do list in our example, the <ul> tag represents our to-do list. Each <li> tag inside it is a to-do item on our list. In JavaScript, we can access these child objects using the children property. The children property is a way to access all the child elements of a specific parent element, in this case, our to-do items within the to-do list.

Here's how you can use it:

JavaScript
1const todoList = document.getElementById('todo-list'); 2const todoItems = todoList.children;

With this code, we first get the todo-list element using document.getElementById('todo-list') and store all its child elements (our to-do items) in the todoItems variable using the children property. This way, you can inspect and use information about your to-do items directly in your JavaScript code.

For example, if todo-list contains three to-do items, todoItems will be an HTMLCollection containing these three <li> elements. You can then manipulate these child elements using various JavaScript methods.

Converting HTML Collections into Arrays

Now that we can access the children of todoList, let's convert them into an array to use powerful array methods. Even though the children property gives us a list-like collection of our to-do items, it's not a real JavaScript array. It's an HTMLCollection, and while it might look like an array, it doesn’t have all the methods that a true JavaScript array has. For example, you can't use the indexOf or forEach methods on an HTMLCollection.

Think of Array.from like converting a guest list from a handwritten sheet (HTMLCollection) to a digital spreadsheet (Array). Now, you can sort, filter, and analyze the list easily. With Array.from(todoList.children), we can convert our HTMLCollection into a real JavaScript array. This allows us to use all the powerful methods an array has.

Here's a small example:

JavaScript
1const todoList = document.getElementById('todo-list'); 2const todoArray = Array.from(todoList.children); 3 4todoArray.forEach(function(todoItem, index) { 5 // Example operation: Setting the text of each todo item to "Task " followed by its index 6 todoItem.textContent = `Task ${index + 1}`; 7});

In this example, forEach() is used to iterate over each todoItem in the todoArray. The operation being performed is setting the text of each todo item to "Task " followed by its index in the array, effectively renaming each item in the list.

Finding Index of a List Item

Sometimes, you might need to know the position of a to-do item within the list. This is where indexOf becomes useful. The indexOf method can be used on arrays to get the index of an element. When used with Array.from(todoList.children), it allows us to find the position of any list item.

Here is an example of how it works:

JavaScript
1function findItemIndex(item) { 2 const todoList = document.getElementById('todo-list'); 3 const index = Array.from(todoList.children).indexOf(item); 4 return index; 5}

In this example, we define a findItemIndex function that returns the position of a to-do item. We convert the children property to an array with Array.from(todoList.children) and then use indexOf(item) to get the item's index.

Using insertBefore function

When working with lists, you may often find the need to move items around. The insertBefore method allows you to insert an element before another one. It's important to note that indices in JavaScript arrays start at 0, so the first element has an index of 0, the second element has an index of 1, and so forth.

Here's an example of how to use it to move a to-do item one place up in the list:

JavaScript
1function moveUp(item) { 2 const todoList = document.getElementById('todo-list'); 3 const index = Array.from(todoList.children).indexOf(item); 4 5 // Check if the item is not already at the top of the list 6 if (index > 0) { 7 // Insert the item before the one above it 8 todoList.insertBefore(item, todoList.children[index - 1]); 9 } 10}

In this example, todoList.insertBefore(item, todoList.children[index - 1]) will move the item one place up. The second argument of insertBefore is the element before which the item will be inserted. If we want to move down, we would reference the element below, and we must also check not to exceed the list's boundaries.

Deep Dive into the insertBefore Function for Reordering

Let's take a closer look at using insertBefore for reordering items. Consider the list: [A, B, C, D, E]. To move an item, say "C", to a position higher up the list, we would use todoList.insertBefore(item, todoList.children[index - 1]). You can visualize this with the * in the list [A, *, B, C, D, E] before moving. As you can see, this places "C" right before "B," resulting in [A, C, B, D, E].

However, to move "C" down one position in the list, you would not use index + 1. While moving "C" up places it before "B", moving "C" down would place it after "D". Since the function is insertBefore, we need to find the index of the item "C" would be placed in front of, which is "E," with index index + 2.

Another way of looking at it is with the following list: [A, B, *, C, *, D, E]. Inserting "C" before the item at index, which is "C", would result in the left *. Inserting "C" before the item at index + 1, which is "D", would result in the right *. Evidently, neither will affect the position of "C" in relation to the other elements in the list.

To summarize:

  • Moving "C" up to before "B" uses index - 1, clearly referencing the element directly before which to place "C".
  • Moving "C" down to after "D" requires index + 2 because inserting "C" after "D" means placing it before the next element, "E".

Understanding this mechanism allows us to reorder items dynamically and accurately in our to-do list using JavaScript.

Combining Concepts: Reordering with Buttons

Now that we've discussed how to access child elements, convert HTMLCollections into arrays, find the index of items, and move items within a list, let's put everything together. We'll enhance our to-do list functionality by adding buttons to move items up or down.

We will focus on the upBtn, downBtn, and move functions.

Here’s the code structure:

JavaScript
1function move(item, directionUp) { 2 const todoList = document.getElementById('todo-list'); 3 const todoArray = Array.from(todoList.children); 4 const index = todoArray.indexOf(item); 5 6 if (directionUp && index > 0) { 7 // Move the item up 8 todoList.insertBefore(item, todoList.children[index - 1]); 9 } else if (!directionUp && index < todoArray.length - 1) { 10 // Move the item down 11 todoList.insertBefore(todoList.children[index + 2], item); 12 } 13}

To implement buttons for moving items up and down in the to-do list:

JavaScript
1const upBtn = document.createElement('button'); 2upBtn.textContent = '^'; 3upBtn.addEventListener('click', function() { 4 move(li, true); 5}); 6 7const downBtn = document.createElement('button'); 8downBtn.textContent = 'v'; 9downBtn.addEventListener('click', function() { 10 move(li, false); 11}); 12 13li.appendChild(upBtn); 14li.appendChild(downBtn);

The move function reorders to-do items by taking the item and the direction (up or down) as arguments. It converts the list's children to an array to find the item's index and uses insertBefore to move the item based on its index and the specified direction.

For the upBtn and downBtn, event listeners are added to call the move function with true (for up) and false (for down) when clicked. These buttons are attached to each list item (li). This setup allows users to dynamically reorder items, making the to-do list more interactive and flexible.

Lesson Summary

In summary, we explored how to access child elements, convert those elements into arrays for more functionality, find indices of items, and reinsert items in different positions using insertBefore. The next exercises offer an opportunity for you to apply and practice your newly acquired knowledge. Let's get to it!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.