James Bateson Personal Site: Post

Building a simple todo app with Vue.js

Over the last few weeks, I’ve started to learn Vue.js, a progressive JavaScript framework. Alongside working through the Frontend Masters course, I decided to try and rebuild my very basic todo app functionality with it.

My app (Today) is a simple todo app - often a go-to build when starting to learn a new language. I'd started to build it using vanilla JavaScript and Electron. Whilst getting my head around Vue I realised that my core functionality needs would be suited to using Vue for, also some of my JavaScript had started to get a little unwieldy!

Today has 4 main actions:

  • Display todos
  • Add a new todo
  • Complete a todo
  • Delete a todo

This post will detail how I went about using Vue to achieve each of these.

Note permalink

This post will not go into, or apply any styling to the todo list, or detail any of the Electron implementation (I'll cover those in a further, more in-depth post once it's all good to go).

Here's the finished Codepen of what I built (see the note above about styling etc)

See the Pen Today (Vue functionality concept) by James Bateson (@jim-bateson) on CodePen.

Creating the Vue Instance permalink

The first thing we need to do is attach Vue to a DOM node

new Vue({
	el: '.js-todo-app'
});

Displaying the todos permalink

For this demo, I've used some dummy data, when I integrate this with my Electron codebase, I'll need to read and write from a JSON file.

Vue reads all data from its data object. So in here, we define our todos array

data: {
	todos: [
	    {
		    title: 'Test todo',
		    completed: false
	    },
	    {
		   title: 'Test todo 2',
		   completed: false
	    }
	]
},

To loop through this data and display it, we need to to use v-for

<li v-for="(todo, index) in todos">
     {{ todo.title }}
</li>

Here todos is the array we are looping through and todo is our name for the array element we are iterating over. You can also pass an (optional) second option to v-for, which is the index of the item.

Add a new todo permalink

This is where my Vue implementation slightly deviates from the initial vanilla/Electron setup I have. In which Electron creates a new window (view) in which you add a new todo, which is then sent to the main window. However, using Vue things can be made much simpler and handled by the framework.

Firstly let's create an input to enter the new todo (make sure to add an associated label for the input)

<label for="add_todo">Add a new todo</label>

<input type="text" id="add_todo" v-model="newTodo" @keyup.enter="addTodo" name="add_todo" placeholder="Today I want to...">

There are a couple of Vue bits we are attaching to this input:

  • v-model is a two way binding on elements such as input and textarea. Depending on the element, it detects the value/status and passes this data to/from Vue. More info here.
  • @keyup.enter (can also be written v-bind:enter) this is an example of a Vue event handler, in this instance pressing the enter key. When this is done, our AddTodo method will be run. Pushing the new todo to the todo array (we defined in data).

Completing a todo permalink

To enable us to complete a todo, there are a couple of things we'll need to setup.

Firstly let's add the element we'll use to action the complete. In this case that's going to be a checkbox.

<label>
    <input type="checkbox" v-model="todo.completed">
    <span>Make a brew</span>
</label>

Here we are setting the v-model to the completed property from our data, this means on checking/unchecking the input set that to true/false.

In anticipation of adding some styling to these completed items, we will then make use of Vue's class bindings on the todo item itself.

<li class="todo-item js-todo-item" :class="{ 'todo-item--completed' : todo.completed }">...</li>

We already have a couple of classes on the <li> this might be for some styling and/or custom JavaScript functionality (they're not important for this demo). Vue allows us to conditionally bind classes (and styles) based on certain conditions being met. Here we're using a ternary to add the todo-item--completed class if the todo has been completed (based on the value of our model).

Deleting a todo permalink

Once a todo has been completed, or if one is added by mistake, it may need to be deleted. To do this we need to remove it from the data (array).

As of v2.2.0 Vue has a handy delete method built-in.

First let's create a button that will trigger this.

<button @click="deleteTodo(index)">Delete todo</button>

Then create a method in our instance.

deleteTodo(index) {
    this.$delete(this.todos, index);
}

We start by passing index as an argument of the method (as defined in our event in the HTML), then use Vue delete. The first argument being the array we are removing the item from and the second using the index we passed into our method.

Todo or not todo? permalink

So we now have our 4 main, core pieces of functionality needed to build a simple todo app! It's a great intro to Vue, using many of the core principles available in the framework.

I'll be expanding on this write up when I finish the app and integrate with Electron and get the app packaged up. But here we have a great start to take a todo list in any direction you wish. It could even be implemented into an existing codebase as I have done - which is one of the great things about Vue!

There are a couple of bits of functionality I'd like to add at some point:

  • Don't let a user add duplicate todos
  • Sorting options (priority etc)
  • Warnings for stale todos
  • Categorising todos
  • Editing a todo (inline)

Hey! I also made this permalink

As well as going through the Frontend Masters course (linked in the intro), I've found the Vue docs site to be very clear, with some great practical examples. I also made this summary pen of directives and bindings to help me remember things.

See the Pen Directives & Data Rendering by James Bateson (@jim-bateson) on CodePen.