July 12, 2016

How to Build a To-Do App in Vue.js - Part 2

by Lamin Sanneh

How to Build a To-Do App in Vue.js - Part 2

This is the second part of a two-part series on building a Vue.js Todo Application. 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 todo-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 todo 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.

Protect your Vue App with Jscrambler

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 on, add in 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 setup 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 isEditing to true. There is a conditional in the template which 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 which triggers the method deActivateInEditMode. This method sets the property isEditing to false and thus hides the form. We also have a checkbox which 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 and 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 send 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. But 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.

Learn how to protect your Vue applications against code theft and reverse-engineering by following this guide.

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 like 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 here.

Finally, 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 by following our guide.