Draft

The Rest

Ben Taylor

converts food and water into pixels and code.

Making a Todo List App

Modern client-side web frameworks often use the todo list application as a sort of "hello world" tutorial application. Todo list applications can be very minimal or heavily featured, allowing us to slowly expand our project. The following tutorial assumes no knowledge of HTML, CSS or JavaScript, however there is quite a bit of content without a lot of explanatory material, so you may need help understanding what is going on.

Introduction

I've broken this tutorial down in to three parts, plus some extension tasks. First off you'll create a minimalistic todolist application, next you'll reorganise and style the application and finally you'll learn how to save the application state locally.

This is the sort of task you could run in class, either over multiple lessons, with seperate parts as homework or with extensions as an assessment. Supplementary material introducing HTML, CSS & JavaScript individually would likely be necessary.

Completed versions of each part can be downloaded here.

If you don't have a text editor appropriate for programming, you should download one now. On both Windows and OS X I recommend Sublime Text.

Create a folder somewhere for this tutorial and then create three folders within it Part 1, Part 2 and Part 3.

Part 1 — Let’s Make an App

The first step to any web project is to create the basis of our html. We'll start off with a very simple HTML5 page. You should add the below code to a file called todolist.html in your Part 1 folder.

<!DOCTYPE html>
<html>
  <head>
    <title>My Todolist</title>
  </head>
  <body>
    <h1>My Todolist</h1>
  </body>
</html>

If you open this html file in your favourite modern browser you'll see a page with a title (in the top of the browser) and a heading. Let's have a look at the different pieces that make up a html document.

At the very top we have <!DOCTYPE html> this tells the browser that following is HTML. Previously this was used to indicate what version (e.g. HTML 4.0 or XHTML), however now HTML has switched to rolling versions focusing on features rather than big releases.

Next you'll see a section that starts with <head> and ends with </head>. In HTML we call these tags and they “open” and “close”. What you're seeing here is the opening <head> tag, information about the page and then the closing <head> tag. The head section of a HTML page stores metadata Extra information about the data. (like the title of the page) which isn't rendered within the browser frame. Take a look at the source code of this page by right-clicking and then clicking "View Page Source" (or similar) to see an example of what can go in the head.

Below this is the <body> of the document. This is where the content of the page lives. Inside it you'll see a <h1>, which is short for "Heading 1". Most elements represent what they sound like, for example a <button> tag will create a button. Any that look a bit mysterious I'll introduce with a description.

Adding a form

Let's move on and add the beginnings of our todolist app. There's going to be two main parts to it, a form where you enter tasks to complete and a list of tasks you need to complete. The form will add items to our list for us to check off.

The form will be relatively simple, we'll need an input element to capture the task name and a button to trigger it being added. Place the following code after your heading.

<form>
  <label>
    Task Name:
    <input type="text" placeholder="Pick up milk">
  </label>
  <button type="button">
    Add Task
  </button>
</form>

If you refresh the page now you'll have the beginnings of our todolist app. It won't do anything, but there'll be an area to write task names and a button to trigger them being added.

Within websites the form tag is usually used to submit data to the server. In this case we aren't actually going to be submitting any data to a server, so it is instead being used as a semantic way of grouping these elements.

The label tag represents the label for an input tag. Clicking any element within the label tag will focus the contained input element. The input element is where our tasks name will be entered.

You may have noticed something strange about the input tag. It doesn't have a closing tag. An input tag doesn't contain anything, so it lives by itself with no closing tag. In XHTML tags like this were “closed” like <input/> however this is no longer necessary.

There are a few other new things here, within the input and button elements, namely attributes. These are values set within the opening tag. For the input tag we are saying that it has a type of text, input elements can also have other types like password (try it out!).

The button tag has a type of button which seems a little redundant, but is actually used to indicate that this should behave as a button rather than submitting the form. Have a look at what happens when you remove that type.

Sample list item

So when we click the “Add Task” button we'll want items to appear in a list. Let's have a look at what that HTML will look like. Below our form add the following code.

<ul>
  <li>
    <label>
      <input type="checkbox">
      Collect underpants
    </label>
  </li>
  <li>
    <label>
      <input type="checkbox">
      ???
    </label>
  </li>
  <li>
    <label>
      <input type="checkbox">
      Profit
    </label>
  </li>
</ul>

When you open this up now, you'll notice that you have a list and a form for adding items to the list. But they aren't really connected (which isn't too useful). We'll get on to that, but let's look at what's going on here.

We've seen label and input before so let's not worry too much about them. The checkbox value for type is new, but fortunately relatively straightforward.

The new and exciting things here are ul and li. Our friend ul is short for unordered list, while li is short for list item. They are simply the way we describe a list that has no specific order. The ordered counterpart is ol short for ordered list. You can try switching the ul with ol to see how an ordered list is rendered.

Making it dynamic

For the next bit we'll need to change a few things around. For this page to be interactive we'll need some places to hook our JavaScript in. The easiest way to reference elements in the document from javascript is through a thing called an id this is an identifier used to uniquely identify a particular element on the page.

Copy over your existing body code with the following snippet.

  <form>
    <label>
      Task Name:
      <input id="new-task-input" type="text" placeholder="Pick up milk">
    </label>
    <button type="button" id="add-task-button">
      Add Task
    </button>
  </form>
  <ul id="todolist-container">
  </ul>
  

With this change all the important bits of our HTML code have had an id assigned to them. We'll now be able to reference the input to retrieve the name of the task, the button for adding the task and the ul for containing the list.

So let's get on to the interactive bit! Place the following script right at the bottom of the body, but before the </body> tag.

  <script>
    var addTaskButton = document.getElementById("add-task-button");
    var newTaskInput = document.getElementById("new-task-input");
    var todolistContainer = document.getElementById("todolist-container");

    addTaskButton.addEventListener('click', function(event) {
      var taskName = newTaskInput.value;
      newTaskInput.value = "";
      todolistContainer.insertAdjacentHTML('afterbegin', taskName);
    });
  </script>
  

Depending on your level of experience with javascript, this may look very familiar, or rather intimidating. The first three lines are quite straightforward. We're creating three new variables to use as references to our important elements.

The next section is a little more complex, we're taking our Add Task button and adding an event listener to it. The event listener is the indented section of code that starts with function. This is a section of code that will be triggered when the button is clicked.

Within that event listener block we're first retrieving the value of the newTaskInput – this is the text they've entered as their task name. Once we've retrieved the text they entered, we clear it out so they can type something else. Then using insertAdjacentHTML we add the name of the task to our list.

Now with checkboxes

So you've tried this out and it's kind of cool. It adds items to a list just as we wanted, but they're all bunched up against eachother and there's no real way for us to indicate which items we've completed. That's because we're just adding text in to the container. What we actually want to do is add li elements like our earlier list. This is a little involved and we'll do it with two steps.

First add the following script tag just above our previous one.

<script type="text/template" id="list-item-template">
<li>
  <label>
    <input type="checkbox">
    <!-- TASK_NAME -->
  </label>
</li>
</script>

This script tag will act as a template for our javascript. We'll retrieve the content of this script tag and then change the bit that says <!-- TASK_NAME --> so that it has our tasks name in it. Next up let's rewrite our original script tag to look like the following.

  <script>
    var addTaskButton = document.getElementById("add-task-button");
    var newTaskInput = document.getElementById("new-task-input");
    var todolistContainer = document.getElementById("todolist-container");
    var templateElement = document.getElementById("list-item-template");
    var template = templateElement.innerHTML;

    addTaskButton.addEventListener('click', function(event) {
      var taskName = newTaskInput.value;
      newTaskInput.value = "";

      var taskHTML = template.replace("<!-- TASK_NAME -->", taskName);
      todolistContainer.insertAdjacentHTML('afterbegin', taskHTML);
    });
  </script>
  

The changes here are minimal, but significant. Instead of just adding text to our container, we're adding a big chunk of HTML. By encapsulating that HTML within a script tag we can reference it from our javascript without needing a big string (something you may have experienced if you've done this before). We've actually just implemented an extremely minimalistic templating language to aid our todolist.

Now when you give this a run you'll notice that it behaves a lot more like you'd expect a todo list app. My favourite thing about this app is how short it is (less than 50 lines), yet we've explored quite a few HTML and JavaScript concepts and most importantly made something useful.

If you've found that you followed all the steps above, but yours doesn't seem to work, compare it to the download I provided at the beginning of the page. You'll find the appropriate file in the Part 1 folder.

Part 2 – Making it pretty

To start this off, first copy your existing todolist.html file in to a new directory. If you followed the instructions earlier you should already have a Part 2 folder.

Next create two extra files todolist.js and todolist.css. These will contain our JavaScript and CSS so that we don't keep cluttering up our todolist.html file.

Copy all of the code out of your second script tag (the one that starts with var) and place it in to todolist.js. You can now replace that with the much neater HTML below.

<script src="todolist.js"></script>

Now that we've moved out the JavaScript in to a seperate file, let's reference our CSS. We do this in a similar, but slightly different way. In the head of your document, just before the </head> tag add the following line.

<link rel="stylesheet" href="todolist.css">

As you can see, HTML is a very consistent standard.

Some simple styles

First off let's tidy things up a little. Right now our todolist is stuck at the left of the page, our input is tiny and our typography isn't great. Start your todolist.css file with the following code.

body {
  font-family: helvetica, sans-serif;
  font-size: 16px;
  line-height: 1.4em;

  width: 600px;
  margin: 96px auto;
}

#todolist-container {
  padding: 0;
  margin-top: 64px;
}

#new-task-input {
  width: 360px;
  font-size: 16px;
  line-height: 1.4em;
}

If you've never seen CSS before, then this might look a bit strange. CSS is made up of two main parts the selector and one or more declarations. On the very first line the selector is body this means that any <body> tag should have these styles applied to it. The { and } braces designate the CSS declarations and the ; seperates each declaration.

We then go on to set some typography declarations, font-family is used to specify the font to use (including fallbacks). In this case if helvetica wasn't installed on the users machine, then the page would render with whichever sans-serif typeface it could find.

A font-size of 16px is good for normal usage on the web and because of the way CSS works this font-size will apply to all elements within the body which don't specify their own font-size.

You'll notice that the setting for line-height is 1.4em an em is a relative measure which represents 1.4x the current font-size.

The next declarations restrict the width of the body. This may seem unnecessary, but it's a neat trick. First we restrict the width, then we apply a margin value of auto to make the body centered in the page. If it didn't have the restricted width it wouldn't be centered.

In this case our margin has two values. Elements can have margins at the margin-top, margin-right, margin-bottom and margin-left. We can write this in a few short ways. The standard short way is to write margin: Apx Bpx Cpx Dpx where A, B, C and D represent top, right, bottom and left respectively. We can be even shorter by writing just two values margin: Apx Bpx to represent top & bottom and right & left respectively.

Our next block of styles deals with the #todolist-container. The # here is selector syntax for id, so it will match any elements who have an id of todolist-container. By setting the padding to 0 we make sure each todolist item sits flush against the left.

Getting classy

To do some more interesting things we're missing a few essentials. We can add some classes to our document so that we can add styles which aren't just applied once. A class is a way of designating elements which should look similar, but don't necessarily have the same tag. Update the item template of your todolist.html file to look like below.

<script type="text/template" id="list-item-template">
<li class="task">
  <label>
    <input class="checkbox" type="checkbox">
    <!-- TASK_NAME -->
  </label>
</li>
</script>

We can now add some CSS to style the tasks, like so.

.task {
  list-style: none;
  font-size: 22px;
  line-height: 1.8em;
}

The . syntax is used to indicate this should match a class of the same name. It is used in the same way as #. With this CSS we're making the list elements much larger and more obvious. For completeness let's make the task entry field and button a lot neater.

#new-task-input {
  width: 360px;
  font-size: 16px;
  line-height: 1.4em;
  
  border: none;
  border-bottom: 1px solid #88888;
  margin: 0px 12px;
}

  #new-task-input:focus {
    outline: none;
    border-bottom-color: #0D99FC;
  }

button {
  font-size: 16px;
  line-height: 1.4em;

  border: none;
  border-radius: 3px;

  color: white;
  background: #0D99FC;
}

The newest piece of syntax here is :focus the colon is what's referred to as a pseudo-selector it selects based on the state of an element, rather than the attributes. Other useful pseudo-selector's are hover, active and visited.

The other strange piece here is the way that we're referring to colours. Using hashes to indicate colours isn't common in every programming language's toolkit, but it is common in many of them. The six values are pairs of hexadecimals mapping to RR, GG, BB and allowing for a range of values between 0-255 for each of the red, green and blue components of a pixel's colour. Software like Photoshop will show the hex value of a colour in it's colour picker.

I'll leave it as an exercise for the reader to work out what each of the new declarations means. There are quite a few of them, but hopefully they aren't too cryptic.

Styling from JavaScript

It'd be rather nice if instead of just having a tick-mark next to each task when it was completed we could also strike it through and fade it out. While it isn't good practice to style elements from JavaScript, it's perfectly acceptable to add appropriate classes. So let's try that out now. Add the following code in to your existing JavaScript.

todolistContainer.addEventListener('click', function(event) {
  var targetElement = event.toElement;

  while (!targetElement.classList.contains("task")) {
    targetElement = targetElement.parentElement;
  }

  var checkbox = targetElement.querySelector(".checkbox");

  if (checkbox.checked) {
    targetElement.classList.add("completed");
  } else {
    targetElement.classList.remove("completed");
  }
});

We've definitely reached the point where if you don't know JavaScript and the DOM already then much of this won't make sense. I'll attempt to explain it to assist those halfway there and if you don't understand it - you can always look further into it in your own time.

Because our list items are being dynamically inserted through JavaScript instead of binding the click event handler to each task list item we've bound it to their container. When the event is triggered we walk up the DOM tree (using the parentElement attribute) until we find the .task element. We need to do this because the user could have clicked on the checkbox or on the text. Place a console.log(targetElement) after the second line if you want to see this behaviour yourself (then check the developer console).

Next we retrieve the .checkbox element so that we can see if it is checked (because they could be checking or unchecking the item). If the task has been completed then we give it the class completed otherwise we remove the class completed. Adding a class multiple times or removing a class multiple times won't have any bad behaviour.

To finish this little piece off we need to actually visually style something when the task has been marked as completed. So let's add some CSS for that now, place this below the .task rule block, but indented a little (to indicate that it is related).

.task {
  // ...
}

  .task.completed {
    text-decoration: line-through;
    opacity: 0.5;
  }

Now when you run the code and click a task to indicate that it is complete you'll notice that the text has a strikethrough and the whole task fades out a little.

If you've found that you followed all the steps above, but yours doesn't seem to work, compare it to the download I provided at the beginning of the page. You'll find the appropriate file in the Part 2 folder.

Part 3 – Extension

For those of you who've managed to get this far, I'm setting you a task. Right now when you close your browser or refresh the page all your tasks are lost. This is not very useful, but of course there is a solution. The Local Storage API can be used to store and retrieve String values within the browser, without needing a server on the back end.

As an example, open up your browsers developer console then try out the code below. If you don't know how to do this, follow these instructions.

window.localStorage.setItem("apple pie", "$3.50");
window.localStorage.setItem("banoffee pie", "$4.00");
window.localStorage.setItem("pumpkin pie", "$3.80");
window.localStorage.getItem("banoffee pie");
for (var i = 0; i < window.localStorage.length; i++) {
  var itemName = localStorage.key(i);
  var itemPrice = localStorage.getItem(itemName);
  console.log(itemName, "costs", itemPrice)
}

By piecing together the above code snippets with what we've learned already you should be able to work out a way to have the page load from Local Storage when the page loads and save to local storage whenever an item is clicked.

Extension Hint

In my solution to this problem I do this in a relatively simple way, I store the task name as the key and the value as a boolean of whether the item has been checked or not. To make it easier to work out what the tasks name is I changed the template in HTML to be as follows.

<script type="text/template" id="list-item-template">
<li class="task">
  <label>
    <input class="checkbox" type="checkbox">
    <span class="task-name"><!-- TASK_NAME --></span>
  </label>
</li>
</script>

Then I can easily retrieve the task name in the click event handler like so.

var taskNameElement = targetElement.querySelector(".task-name");
var taskName = taskNameElement.innerHTML;

If you'd like to skip straight to the answers, you can simply look in the Part 3 folder of the code bundle at the top of the page.

So that's how you make a relatively minimalistic Todo List app with HTML, CSS and JavaScript.

Have any comments, recommendations or criticisms? Tweet or email me.