How to Build a To-Do App in Vue.js - Part 2
July 12th, 2016 | By Lamin Sanneh | 7 min read
This is the second part of a two-part series on building an App in Vue.js In the first part, we touched on how to supply data to templates from a component class, loop over data in the templates, and more.
In this second part, we will see how to handle events coming in from the template which will allow us to create more Todos, edit them, and eventually delete them.
Forms, Methods, and Events
So carrying on from the first part, we can now display a list of Todos. Let's create our final component so that we can create, edit, and delete Todos.
Adding a New Todo Component
Create a new Todo component by creating a file in src/components/Todo.vue. Leave it empty for now.
Modify the main App.vue component template by adding a form after the to-do list invocation. So it should look like this:
<div class="container" id="app">
<div class="page-header">
<h1>Vue.Js Todo App</h1>
</div>
<todo-list v-bind:todos="todos"></todo-list>
<form v-on:submit.prevent="addNewTodo()">
<div class="form-group">
<input -av-model="newTodoText" type="text" class="form-control" name="name" placeholder="Enter new Todo here">
</div>
</form>
</div>
Add a method to its component class. Vue.js puts methods in a class underneath a methods property.
methods: {
addNewTodo() {
if (this.newTodoText.length > 0) {
this.todos.push({
title: this.newTodoText,
done: false
})
this.newTodoText = ''
}
}
}
What is happening here is that we are binding the form input value to the newTodoText property in the class.
<input v-model="newTodoText" type="text" class="form-control" name="name" placeholder="Enter new Todo here">
We are also adding an event handler named addNewTodo in our class. This is called when the new to-do form is submitted through the line below.
<form v-on:submit.prevent="addNewTodo()">
Now, anytime we submit the form, a new todo gets added to our list, and the new todo input field gets cleared.
Editing a Todo
To be able to edit a todo, we need to create a new Todo component. In the empty Todo component file created earlier, add the following content.
<template>
<li class="list-group-item">
<div class="row">
<div class="col-md-8">
<div class="todo-title" v-on:click="activateInEditMode" v-show="!isEditing" >
{{ todo.title }}
</div>
<form v-show="isEditing" v-on:submit.prevent="deActivateInEditMode" >
<div class="form-group">
<input v-model="todo.title" type="text" class="form-control" >
</div>
</form>
</div>
<div class="col-md-4">
<span class="btn btn-default" v-on:click="removeTodo(todo)">remove</span>
<span v-if="todo.done" class="bg-success todo-status">Done</span>
<span v-else="todo.done" class="bg-danger todo-status">Not Done</span>
<input v-model="todo.done" type="checkbox">
</div>
</div>
</li>
</template>
<script type="text/javascript">
// <![CDATA[
export default {
props: ['todo'],
data() {
return {
isEditing: false
}
},
methods: {
activateInEditMode() {
this.isEditing = true
},
deActivateInEditMode() {
this.isEditing = false
}
}
}
// ]]>
</script>
<style scoped>
<!-- -->
</style>
In the Todo Component here, we have set up a class with a property isEditing. This will be responsible for deciding whether the Todo is in edit mode or not. We have an event handler on the Todo title in the template. This triggers a method in the class called activateEditMode when the title gets clicked.
This method will set the data property editing to true. There is a conditional in the template that shows the Todo title when the isEditing property is false. It shows the edit form when it is true as shown below.
<div class="todo-title" v-on:click="activateInEditMode" v-show="!isEditing" >
{{ todo.title }}
</div>
<form v-show="isEditing" v-on:submit.prevent="deActivateInEditMode" >
<div class="form-group">
<input v-model="todo.title" type="text" class="form-control" >
</div>
</form>
When in edit mode, the form, when submitted has an event handler that triggers the method deActivateInEditMode. This method sets the property isEditing to false and thus hides the form. We also have a checkbox that toggles the done status of the Todo, showing and hiding the divs accordingly as shown below.
<span v-if="todo.done" class="bg-success todo-status">Done</span>
<span v-else="todo.done" class="bg-danger todo-status">Not Done</span>
<input v-model="todo.done" type="checkbox">
Now that we have an editable Todo, we have to modify the TodoList to make use of the new editable Todo Component. Replace the TodoList template with the code below:
<p>
Total Todo Count <span class="badge">{{ todos.length }}</span>
</p>
Here, we are looping over the list of Todos instead of just showing the title as before. We are creating an instance of a Todo Component and passing in a Todo object in each case in this line.
<ul class="list-group">
<todo v-on:remove-todo="removeTodo" v-for="todo in todos" :todo.sync="todo" ></todo>
</ul>
The part v-on:remove-to="removeTodo()" just calls the removeTodo function anytime a child element sends up an event with the name remove-todo.
We will get to the usage of that in the next sub-section. To make sure the TodoList can use this component in its template, we must import it. First, add this to the top of its script tag.
import Todo from './Todo'
Next, add the imported Todo as a property of the components object. This shows our intent to make use of the component in this class.
export default {
props: ['todos'],
components: {
Todo,
},
};
Now we have the main TodoList component making use of the individual Todo component.
Deleting a Todo
Let’s add functionality to be able to delete a Todo. Add this to the template of the Todo Component at the top part of the div with the class of col-md-4.
<span class="btn btn-default" v-on:click="removeTodo(todo)">remove</span>
This adds a button to delete a Todo. Also, add a method to the component class to handle clicking on the button. This calls the removeTodo and passes the current Todo to delete.
removeTodo (todo) {
this.$dispatch('remove-todo', todo)
}
The removeTodo method sends an event named ‘remove-todo’ to the parent TodoList Component. However the parent does not have a handler for the event, so add this to the TodoList Component class.
methods: {
removeTodo(todo) {
const todoIndex = this.todos.indexOf(todo)
this.todos.splice(todoIndex, 1)
}
}
We have to send the event upwards to the parent because it has access to the Todo list. This is so we can remove the desired Todo from that list. Now when you click on the remove button, the corresponding todo disappears from the screen.
Component Styles
Add this CSS to the styles section of the Todo component to style the Todo titles appropriately.
.todo - title {
cursor: pointer;
padding: 6 px;
margin - bottom: 15 px;
}
.todo - title: hover {
background - color: #F1EDED;
}
The scoped property on the style tag is a way to tell Vue.js to only apply these styles to elements in this component only. This is useful for introducing new components into an already existing application without affecting other components.
Integrating with Jscrambler
Security wise, you could use Jscrambler’s Domain Locking feature to make sure the code only runs on your chosen list of domains.
If that isn’t enough, you could add an extra layer of security by thwarting any debugging attempts made on the code using Jscrambler’s Self-Defending feature.
Conclusion
Now, we have a complete Todo Application. Even though this is a detailed Vue.js article, I urge you to have a look at the documentation to see what else you could achieve with this marvelous framework. For example, server-side storage of the Todo data, animations, and more.
In my opinion, Vue.js has a nice balance between configuration and convention. Whereas other frameworks, for example, Ember.js are heavily convention-based, Vue.js likes to let you make some choices for example in terms of folder structure. It lets you structure your app anyhow because you can put templates and classes in a single file.
This brings us to the end of the article. Thank you for reading.
You can find the code for this tutorial.
Don't forget to pay special attention if you're developing commercial Vue apps that contain sensitive logic. You can protect them against code theft, tampering, and reverse engineering.
Jscrambler
The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.
View All ArticlesMust read next
How to Build a To-Do App in Vue.js - Part 1
In the first part of the Todo Application, we will cover how to setup Vue.js, setup a simple component.
July 8, 2016 | By Lamin Sanneh | 7 min read
Build a Task List with Authentication Using SQL, Node.js and Adonis (Part 1)
In this tutorial, we create a Node.js server that communicates with a MySQL database to render a browser task app. We’ll add authentication using Adonis.
August 17, 2018 | By Connor Lech | 10 min read