A Simple Client

Why use a framework? I'll just write my own in a weekend.
- Seconds before disaster

The Requirements

One day you sit around and dream about sunshine as suddently the dreaded Project Manager approaches you and asks you to build a small task application. The application should consist of a list showing the current tasks. Additionally, a web form should allow the user to create a new task (which should then be displayed in the list of current tasks).

The Initial HTML

You get to work and quickly come up with the initial document:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Task List App</title>
  </head>
  <body>
    <h1>Task List</h1>

    <!-- Task List -->
    <ul id="task-list"> </ul>

    <!-- Form to Add Tasks -->
    <h2>Add a Task</h2>
    <form id="task-form">
      <label for="task-input">Task:</label>
      <input type="text" id="task-input" placeholder="Enter your task" />
      <button type="submit">Add Task</button>
    </form>

    <!-- JavaScript will go here -->
    <script></script>
  </body>
</html>

You now have a heading, a list and a form. However if you click the submit button, not a whole lot happens - this is because we haven't added any submit logic to the form yet.

Grabbing the Items

Lets first grab the relevant items (remember that the code goes between the <script></script> tags). This can be done using the querySelector method. In this case we want to select by ID, so we use the # selector:

const taskList = document.querySelector('#taskList');
const taskForm = document.querySelector('#taskForm');

Adding an Event Listener

Next, we need to add an event listener to taskForm.

The event.currentTarget will have the property elements which contains taskInput whose property value contains our input:

taskForm.addEventListener('submit', function (event) {
  // Prevent default form submission
  event.preventDefault();

  console.log({ inputValue: event.currentTarget.taskInput.value });
});

This should log the input.

Lets now store it in a variable and use trim to remove whitespace from both ends:

taskForm.addEventListener('submit', function (event) {
  // Prevent default form submission
  event.preventDefault();

  const task = event.currentTarget.taskInput.value.trim();
});

Finally we will use the createElement method to create a new li element and the appendChild method to add the newly created element to our task list:

taskForm.addEventListener('submit', function (event) {
  // Prevent default form submission
  event.preventDefault();

  const task = event.currentTarget.taskInput.value.trim();

  const li = document.createElement('li');
  li.textContent = task;
  taskList.appendChild(li);

  // Clear the input field
  event.currentTarget.taskInput.value = '';
});

When you now click the button, you will see that a new task will be added.

Adding a Delete Button

As you complete the project, the Project Manager once again walks up to you and remembers that it might be a good idea to allow the user to delete tasks. So now you need to add a delete button.

This means that whenever you create a new element, you need to add a delete button to it. To accomplish this we first need to create the delete button:

const li = document.createElement('li');
li.textContent = task;

// New code starts here

const deleteButton = document.createElement('button');
deleteButton.textContent = 'Delete';

Then we need to attach an event listener to the delete button:

deleteButton.addEventListener('click', function () {
  taskList.removeChild(li);
});

Finally we need to add the delete button to the task item:

li.appendChild(deleteButton);

Quite a lot of work to just add a little delete button. Additionally our code is now all over the place and not really reusable. This doesn't seem like it will scale to a larger application.

To simplify our lives, we will use a library called React. The idea behind React is to create declarative UIs with nicely separated components. Basically we only define how the application should look like (hence the declarative aspect) and React takes care of the rest, such as determining the necessary DOM manipulations. As you will see soon, this is an incredibly useful feature.