To-Do List (Not A Guide – Just Me Trying To Make One)
Tags: codenewbie, javascript
Published: 2021-02-01 21:56:38

**01/02/2021**

###**Introduction**

This is not a tutorial on how to make a to-do list app. This is just a code newbie typing out their thought process as he may or may not descend into madness while trying to make one.

###**Thought Stream**

First I’ll need to set up a form in the HTML so that I’ll be able to type what I want to add to the to-do list:


```HTML
    <div class="container">
      <h1>To-Do List</h1>
      <form>
        <label for="entry">Add something to the to-do list:</label><br /><br />
        <input ="text" id="input" name="entry" />
        <button type="submit" id="add">Add</button>
      </form>
      <ul id="todoListID" class="todoList"></ul>
    </div>
```


![Blurry image of the start of the to-do list](https://i.imgur.com/Y4kf7Ma.png)


Next up is to find out why that screenshot that I just copy and pasted into LibreOffice Writer is so blurry. After some Googling it looks like you need to use an image editor to remove the alpha channel/transparency and then when you copy and paste it into Writer it won’t be blurry. I’m not going to do that. I’ll just save them in Microsoft Paint instead of this document as I’ll need to upload them to the blog separately anyway.

![Non blurry image of the start of the to-do list](https://i.imgur.com/j2IYqZB.png)

___


Now it’ll need some JavaScript to make it functional. I’ve added comments to every line to save me explaining it here:

```javascript
const todoListID = document.getElementById("todoListID"); // gets the <ul> "To-Do List"
const add = document.getElementById("add"); // gets the "Add" button

add.addEventListener("click", function (event) {
  event.preventDefault(); // prevent the default action of the button from submitting the form
  let input = document.getElementById("input"); // gets the input field
  let newEntry = document.createElement("li"); // creates a new list item
  newEntry.innerText = input.value; // sets the new list item text to the same value as the input field
  todoListID.appendChild(newEntry); // adds the new list item to the unordered list in the HTML (the to-do list)
});
```
![To-do list with test items](https://i.imgur.com/43rPYus.png)

Good stuff.

---

Now the items will need buttons so that items can be crossed off or removed from the list:

`newEntry.innerText = input.value;`

becomes:

`newEntry.innerHTML = input.value + '<button>hello</button>';`

I changed “innerText” to “innerHTML” so that I can include a button alongside the item. Let’s see if it worked:

![To-do list with test items with buttons](https://i.imgur.com/R7hTN9i.png)

Close enough. Aligning the button to the right hand side so that it isn’t so close to the text will probably be a nightmare so I’ll leave it like that for now.

---

Next I’ll need some more JavaScript to make the button work but I’m sensing danger. If I give the button an ID so that I can use an `eventListener` on it, I’ll probably get an error because the button doesn’t exist when the page loads, it only exists after the user has added an item:

```javascript
add.addEventListener("click", function (event) {
  event.preventDefault();
  let input = document.getElementById("input");
  let newEntry = document.createElement("li");
  newEntry.innerHTML = input.value + '<button id="test">hello</button>'; // here I have added an ID to the button so that I can hopefully add an eventListener to it
  todoListID.appendChild(newEntry);
});

const test = document.getElementById("test");
test.addEventListener("click", function () {
  console.log("testing");
});
```

> Uncaught TypeError: test is null
> <anonymous> http://127.0.0.1:5500/main.js:16

Yep. Maybe if I put the new `eventListener` inside the other `eventListener` it will work?

```javascript
add.addEventListener("click", function (event) {
  event.preventDefault();
  let input = document.getElementById("input");
  let newEntry = document.createElement("li");
  newEntry.innerHTML = input.value + '<button id="test">hello</button>'; // here I have added an ID to the button so that I can hopefully add an eventListener to it
  const test = document.getElementById("test");
  test.addEventListener("click", function () {
    console.log("testing");
  });
  todoListID.appendChild(newEntry);
});
```

Nope.

> Uncaught TypeError: test is null
> <anonymous> http://127.0.0.1:5500/main.js:12
> EventListener.handleEvent* http://127.0.0.1:5500/main.js:4

In the past I’ve seen `setAttribute()` used to set IDs on buttons so maybe I’ll give that a shot:

```javascript
let delete = document.createElement("button");
```

Wait. Why won’t it let me do that? Oh, “delete” is a reserved word. Try again:

```javascript
add.addEventListener("click", function (event) {
  event.preventDefault();
  let input = document.getElementById("input");
  let newEntry = document.createElement("li");
  newEntry.innerHTML = input.value;
  let deleteEntry = document.createElement("button");
  deleteEntry.setAttribute("id", "delete");
  newEntry.appendChild(deleteEntry);
  todoListID.appendChild(newEntry);
});
```

![To-do list with strange buttons](https://i.imgur.com/473PLap.png)

Looks like I’m going way off course here. I’ll just try `onclick()` even though I’ve read it’s bad practice. It can’t be that bad if it works though:

```javascript
  newEntry.innerHTML = input.value + '<button id="test" onclick="testing()">hello</button>';

function testing() {
  console.log("test");
}
```

> test

Perfect! Now to rename all the “test” and “testing” so it looks like I never doubted myself. And so that they’ll be more descriptive. But mainly the first thing.

```javascript
newEntry.innerHTML =
    input.value +
    '<button id="deleteBtn" onclick="deleteEntry()">Delete</button>';

function deleteEntry() {
  console.log("deleted");
}
```

---

Next will be to try to make it actually delete the entry. I’m thinking if I can get the target element that was clicked, then I can go from there:

```javascript
function deleteEntry(event) {
  console.log(event.target);
}
```

> Uncaught TypeError: event is undefined
> deleteEntry http://127.0.0.1:5500/main.js:26
> onclick http://127.0.0.1:5500/index.html?:1

Maybe not. Why’s that not working? Oh, I guess that the `onclick()` needs “event” too.

```javascript
  newEntry.innerHTML =
    input.value +
    '<button id="deleteBtn" onclick="deleteEntry(event)">Delete</button>';
```


Wahey! Success.

```javascript
<button id="deleteBtn" onclick="deleteEntry(event)"> 
```

I wonder why that worked though? I guess “event” is the argument when the function is called? So if I change the “event” parameters in the `deleteEntry()` function to make it less confusing, it should still work:

```javascript
function deleteEntry(a) {
  console.log(a.target);
}


<button id="deleteBtn" onclick="deleteEntry(event)"> 
```

OK. But I still don’t know why “event” is defined. Oh maybe it’s from the `eventListener`:

```javascript
add.addEventListener("click", function (event) {
  newEntry.innerHTML =
    input.value +
    '<button id="deleteBtn" onclick="deleteEntry(event)">Delete</button>';
});
```

But if it is, then I have no idea what’s happening. Isn’t this `eventListener` triggered by clicking the “Add” button?

Should I even post this blog? Anyone that reads it will see that I’m a dummy.

Well you’ve already spent 3 hours on it and the to-do list so you might as well. Someone might explain things to you if you’re lucky. And anyone that likes you enough to even read this blog post probably already knows that you’re a dummy anyway.

Good points. Let’s carry on then.

---

Where were we? Oh yeah, the delete button. It’s working but we don’t really know why. No need to let that stop us though. Time to see if we can get it to actually delete the entry:

```javascript
function deleteEntry(a) {
  a.target.parentNode.remove();
}
```

Great success!

Now to add a strikeout effect to completed items. I can’t be bothered dealing with buttons again so I’ll just try to use an `eventListener` on the list:

```javascript
todoListID.addEventListener("click,", function (event) {
  console.log("aaaaaaaaaa");
  console.log(event.target);
});
```

This doesn’t log anything at all in the console when clicking on the to-do list for some reason. Maybe I’ll be lucky and VSCode’s Live Server extension has just stopped working. I’ll restart it and see.

Nope, unfortunately it was working fine. I’ll make a new list to test it. One that already exists on the page:

![To-do list with a separate test list on the page](https://i.imgur.com/9T1nGbA.png)

```javascript
const toDoListID2 = document.getElementById("toDoListID2");

todoListID2.addEventListener("click,", function (event) {
```

Nope

```javascript
todoListID2.children.addEventListener("click,", function (event) {
```

Nothing

```javascript
todoListID2.children[1].addEventListener("click,", function (event) {
```

Nada

*20 minutes later*

Still no progress. Let’s just copy some code from the internet then. Found this on www.w3schools.com:

```javascript
var list = document.querySelector("ul");
list.addEventListener(
  "click",
  function (ev) {
    if (ev.target.tagName === "LI") {
      //   ev.target.classList.toggle("checked");
      console.log("aaaaaa");
    }
  },
  false
);
```

Still nothing happens. Oh I think `querySelector()` only returns the first result. So it won’t work on my test list but might work on the real one:

> aaaaaa

Let’s see if we can get it working on the test list then. Oh no. Is that a typo?

```javascript
const toDoListID2 = document.getElementById("toDoListID2");

todoListID2.addEventListener("click,", function (event) {
```

The ID in the HTML is:

```HTML
<ul id="todoListID2" class="todoList2">
```

Disaster. Let’s change that because it’s probably case sensitive and see if it fixes anything. Nope. Is that a good thing or a bad thing?  I guess good because now we can just use that code from w3schools. Maybe `querySelector()` gives us something different to `getElementById()`?

```javascript
const todoListID2 = document.getElementById("todoListID2");
console.log(todoListID2);
```

> < ul id="todoListID2" class="todoList2"> 

```javascript
var list = document.querySelector("ul");
console.log(list);
```

> < ul id="todoListID" class="todoList"> 


Nope. Same type of results. Let’s see if the w3schools code works with `getElementById()` instead of `querySelector()`:

```javascript
todoListID2.addEventListener(
  "click",
  function (ev) {
    if (ev.target.tagName === "LI") {
      //   ev.target.classList.toggle("checked");
      console.log("aaaaaa");
    }
  },
  false
);
```

> aaaaaa

Yep that works. So it must be my code that doesn’t work. Who could have guessed that??? Let’s try it with their code then:

```javascript
const todoListID2 = document.getElementById("todoListID2");
console.log(todoListID2);
todoListID2.addEventListener("click,", function (event) {
  if (event.target.tagName === "LI") {
    console.log("aaaaaaaaaa");
  }
});
```

Still doesn’t work. The only other thing I see that’s different is the “false” parameter:

```javascript
const todoListID2 = document.getElementById("todoListID2");
console.log(todoListID2);
todoListID2.addEventListener(
  "click,",
  function (event) {
    if (event.target.tagName === "LI") {
      console.log("aaaaaaaaaa");
    }
  },
  false
);
```

Still doesn’t work. What the heck is happening here? I’ve had enough of this. I’m taking a break.

---

OK I’m back. Oh I forgot how stuck I was. Whatever, let’s just do it the w3schools way because for some reason that’s the only way it works:

```javascript
let list = document.querySelector("ul");
list.addEventListener(
  "click",
  function (ev) {
    if (ev.target.tagName === "LI") {
      ev.target.classList.toggle("clicked");
    }
  },
  false
);
```

![To-do list strikethrough](https://i.imgur.com/BOPMUb0.png)

Lovely jubbly.

---

What’s next? Style it nicely or try to move the delete button to the right hand side? I’ll try the delete button. I should probably remake the container and use flex or grid to position the button which might make it more responsive but I’m fed up. So I’m just going to add `position: relative` to the `li` and then this to the "Delete" button:

```CSS
.delete {
  position: absolute;
  right: 0;
}
```

![To-do list buttons on the right hand side](https://i.imgur.com/m7U6VHJ.png)

---

Now just need to add some styling and get the heck out of here. Removing the bullet points and changing colour on every other item always makes lists easier to read:

```CSS
li:nth-child(even) {
  background-color: red;
}
```

![To-do list with the even rows in red](https://i.imgur.com/fvOgjcq.png)

But now the background colour doesn’t change when I click on an even item, only the text does:

![To-do list items background problem](https://i.imgur.com/WwEBXi0.png)

So should I try to find out where the CSS specificity is going wrong or just add `!important`? That’s an easy choice:

```CSS
.clicked {
  background: rgb(255, 0, 179) !important;
  color: rgb(0, 255, 42);
  text-decoration: line-through;
}
```

![To-do list items background problem fixed](https://i.imgur.com/BXUIRyF.png)

Now to pick some nicer colours from the internet and space things out a bit. The end.

---

Me again. It’s a new day. Patience has been refilled and there’s problems to fix. It’s possible to click   the “Add” button without any text in the input field, meaning it adds an empty entry to the list. Which I’m fine with. Doing nothing is one of my favourite things to do so I’m not going to disallow it with JS. The problem is that the empty lines aren’t tall enough to contain the “Delete” buttons:


![To-do list short rows](https://i.imgur.com/kzqrinD.png)

Adding a minimum height will hopefully fix that:

```CSS
  min-height: 40px;
```

![To-do list short rows fixed](https://i.imgur.com/7kOI5Qs.png)

---

OK. Next is to be able to add an entry by pressing enter instead of clicking the “Add” button and then set focus back to the input field because it’s annoying moving the cursor back and forth between them. I guess I need to listen for the “enter” key being pressed on the `eventListener`. The keycode for the enter key is 13:

```javascript
add.addEventListener("click", function (event) {
  if (event.keyCode === 13) {
    event.preventDefault();
    let input = document.getElementById("input");
    let newEntry = document.createElement("li");
    newEntry.innerHTML =
      input.value +
      '<button id="deleteBtn" class="delete" onclick="deleteEntry(event)">Delete</button>';
    todoListID.appendChild(newEntry);
  }
});
```

Doesn’t work. The user input vanishes when submitted. Must be to do with `event.preventDefault();` being in the wrong place. I’ll move it up.

Nope. The input doesn’t vanish but it doesn’t get added to the to-do list. Let’s try putting the if statement on its own to check if pressing the enter key is actually working:

```javascript
add.addEventListener("click", function (event) {
  event.preventDefault();
  if (event.keyCode === 13) {
    console.log("aaaaaa");
  }
  let input = document.getElementById("input");
  let newEntry = document.createElement("li");
  newEntry.innerHTML =
    input.value +
    '<button id="deleteBtn" class="delete" onclick="deleteEntry(event)">Delete</button>';
  todoListID.appendChild(newEntry);
});
```

Errr…. Now everything is working as intended somehow. I don’t know how an empty if statement makes that work. I’ll take it out and see what happens. Arggghhh it still works! Which means I could have just used the enter key all along! The focus stays in the input field too. OK I’ve had enough of this again. Bye bye.


![To-do list final image](https://i.imgur.com/5dOE0YT.png)