Learn VueJS by building a simple Todo-App.

Purpose

This article is meant to teach you the basics of VueJS by building a Todo-App, it will be practical and comprehensible. My targeted audience is complete beginners when it comes to JavaScript frameworks but also developers who comes from other frameworks like React and Angular that want’s to learn Vue as well.

Installing VueJS

Installing Vue is as simple as typing in the following line in your terminal, if you don’t have Node installed (which is required to use the npm command), go to Nodejs.org and install the latest version.

$ npm install -g @vue/cli

Creating our project

We will now create our project by running the command down below, it will ask you to pick a preset, choose the default one.

vue create todo-app
cd todo-appnpm run serve

About VueJS and folder structure

I’m not going to get into the details about how VueJS works but basically it’s a Javascript framework used to build Single Page Applications, I encourage you to read more about these types of applications.

The “src” folder

This is the folder we will be working with today. If you have worked with other Javascript frameworks chances are that you have worked with so called components, VueJS also use this concept. Basically every part of the UI in our application is part of a component, these components can be nested, combined and be used in various different ways. When creating a VueJS application the way we did it, a main component called “App” is automaticaly created for you, you can look at the component in “App.vue”.

<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = falsenew Vue({
render: h => h(App),
}).$mount('#app')

The file structure of a component

Before we start building our app I will take a moment to explain how you build your components.

<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
// To make styling only apply to current component:
<style scoped>
</style>

Let’s start building!

Now you know the basics of VueJS and are ready to start building the Todo-App.

<template>
<div id="app">
</div>
</template>
<script>export default {
name: 'app',
}
</script>
<style>
</style>
<script>
export default {
name: 'app',
data() {
return {
todos: [
{
id: 1,
title: 'Go workout',
completed: false
},
{
id: 2,
title: 'Do laundry',
completed: false
},
{
id: 3,
title: 'Cook food',
completed: false
},
{
id: 4,
title: 'Clean up room',
completed: false
},
{
i: 5,
title: 'Finish work',
completed: false
}
],
}
},
}
</script>
<template>
<div>
<h2>My todolist</h2>
</div>
</template>
<script>
import Todo from './Todo';
export default {
name: 'Todos',
components: {
Todo
}
}
</script>
<style scoped>
</style>
<template>
<div>
</div>
</template>
<script>
export default {
name: 'Todo',
}
</script>
<style scoped>
</style>
<template>
<div id="app">
<Todos />
</div>
</template>
<script>
import Todos from './components/Todos';
export default {
name: 'app',
components: {
Todos
},
data() {
return {
todos: [
{
id: 1,
title: 'Go workout',
completed: false
},
{
id: 2,
title: 'Do laundry',
completed: false
},
{
id: 3,
title: 'Cook food',
completed: false
},
{
id: 4,
title: 'Clean up room',
completed: false
},
{
i: 5,
title: 'Finish work',
completed: false
}
],
}
},
}
</script>
<style>
</style>
<Todos v-bind:todos="todos"/>
<script>
import Todo from './Todo';
export default {
name: 'Todos',
components: {
Todo
},
props: [
"todos"
]
}
</script>
<<template>
<div>
<h2>My todolist</h2>
<ul>
<li v-bind:key="todo.id" v-for="todo in todos">
<Todo v-bind:todo="todo" />
</li>
</ul>
</div>
</template>
<template>
<div>
<p>{{ todo.title }}</p>
</div>
</template>
<script>
export default {
name: 'Todo',
props: [
"todo"
]
}
</script>
<style scoped>
</style>
npm install uuid
<template>
<div>
<form @submit="addTodo">
<input type="text" v-model="title" name="title">
<button type="submit">Add</button>
</form>
</div>
</template>
<script>
import uuid from 'uuid';
export default {
name: 'AddTodo',
data() {
return {
title: ''
}
},
methods: {
addTodo(e) {
e.preventDefault();
const newTodoObj = {
id: uuid.v4(),
title: this.title,
completed: false
}
this.$emit('add-todo', newTodoObj);
this.title = '';
}
}
}
</script>
<style scoped>
</style>
<input type="text" v-model="title" name="title">
<form @submit="addTodo">
<input type="text" v-model="title" name="title">
<button type="submit">Add</button>
</form>
addTodo(e) {
e.preventDefault();
const newTodoObj = {
id: uuid.v4(),
title: this.title,
completed: false
}
this.$emit('add-todo', newTodoObj);
this.title = '';
}
<template>
<div id="app">
<Todos v-bind:todos="todos"/>
<AddTodo v-on:add-todo="addTodo"/>
</div>
</template>
<script>
import Todos from './components/Todos';
import AddTodo from './components/AddTodo';
export default {
name: 'app',
components: {
Todos,
AddTodo
},
data() {
return {
todos: [
{
id: 1,
title: 'Go workout',
completed: false
},
{
id: 2,
title: 'Do laundry',
completed: false
},
{
id: 3,
title: 'Cook food',
completed: false
},
{
id: 4,
title: 'Clean up room',
completed: false
},
{
i: 5,
title: 'Finish work',
completed: false
}
],
}
},
methods: {
addTodo(newTodoObj) {
this.todos = [...this.todos, newTodoObj];
}
}
}
</script>
<template>
<div v-bind:class="{ 'completed': todo.completed }">
<p v-on:click="markComplete">{{ todo.title }}</p>
</div>
</template>
<script>
export default {
name: 'Todo',
props: [
"todo"
],
methods: {
markComplete() {
this.todo.completed = !this.todo.completed
}
}
}
</script>
<style scoped>
.completed {
text-decoration: line-through;
}
</style>
<template>
<div v-bind:class="{ 'completed': todo.completed }">
<p v-on:click="markComplete">{{ todo.title }}</p>
<button @click="$emit('delete-todo', todo.id)">Delete</button>
</div>
</template>
<script>
export default {
name: 'Todo',
props: [
"todo"
],
methods: {
markComplete() {
this.todo.completed = !this.todo.completed
}
}
}
</script>
<style scoped>
.completed {
text-decoration: line-through;
}
</style>
<template>
<div>
<h2>My todolist</h2>
<ul>
<li v-bind:key="todo.id" v-for="todo in todos">
<Todo v-bind:todo="todo" v-on:delete-todo="$emit('delete- todo', todo.id)"/>
</li>
</ul>
</div>
</template>
<template>
<div id="app">
<Todos v-bind:todos="todos" v-on:delete-todo="deleteTodo"/>
<AddTodo v-on:add-todo="addTodo"/>
</div>
</template>
<script>
import Todos from './components/Todos';
import AddTodo from './components/AddTodo';
export default {
name: 'app',
components: {
Todos,
AddTodo
},
data() {
return {
todos: [
{
id: 1,
title: 'Go workout',
completed: false
},
{
id: 2,
title: 'Do laundry',
completed: false
},
{
id: 3,
title: 'Cook food',
completed: false
},
{
id: 4,
title: 'Clean up room',
completed: false
},
{
i: 5,
title: 'Finish work',
completed: false
}
],
}
},
methods: {
addTodo(newTodoObj) {
this.todos = [...this.todos, newTodoObj];
},
deleteTodo(todoId) {
this.todos = this.todos.filter(todo => todo.id !== todoId);
}
}
}
</script>
<style>
</style>

Thank you!

I hope you found this article helpful. I encourage you to really go through the code and try to understand it, if your ambitious, maybe even try to build the application all by yourself!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store