# Let's have some fun!

# I. Create the 3 templates

  1. open this codesandbox once you are logged in: Codesandbox template (opens new window) Don't forget to select Auto Save from File menu on the codesandbox editor.

  2. in the src folder you'll find the components subfolder, expand it.

  3. create 3 vuejs files named:

    • TodosInput.vue
    • TodosList.vue
    • TodosActions.vue
  4. In each file add the default template

<template>
</template>

<script>
    export default {
        name: ""
    }

</script>  
  1. Inside each component you created add the name as the file name but without the .vue

Open the App.vue and import the created components inside the script tag:

import TodosInput from "./components/TodosInput";
import TodosList from "./components/TodosList";
import TodosActions from "./components/TodosActions";

Having the components imported we have to let Vue know about them. In order to do this we will add the components inside the components property of the App component.

components: {
            TodosInput,
            TodosList,
            TodosActions
},

It is time to create the content of the first component. The input component that will also contain the title of the vue app.

# II. Create Input component

The creation of the component for our case is going to have 3 steps:

  1. Move the content from app component into TodosInput
  2. Include the component into the app
  3. Add behavior to create todos

Let's move the header tag from App.vue to TodosInput.vue. After moving the content add the todos-input component in the same place.

Replace this:

<header class="header">
    <h1></h1>
    <input class="new-todo" placeholder="What needs to be done?" autofocus>
</header>

with this:

<todos-input />

As we can see the page does not look the same as before and in order to have this fixed we have to send the title from the App.vue to the TodosInput.vue. This is using the props feature of any vue js component. Inside the TodosInput and after the name, add the props with the title as a string type:

,props:{
        title:{
            type:String
            }
        }

This will tell the component that the value of the title will be sent from the parent of the todosinput component. Now we also have to send it. This is done inside the App.vue component where we have to change the todos-input tag like this:

<todos-input :title="title" />

The above line sends the title from the vue component to the todos-input component.

You can change the value of the title from inside the App.vue component with a value of your own. After the change the title will be updated.

It is time to work on adding new todos. We can do this using the $emit feature of vue.

Open the TodosInput component and update the input tag with the following:

@keyup.enter="createTodo"

Then in the script part of the component add a new property named methods with the following content:

, methods:{
        createTodo(ev){
            this.$emit('createTodo',ev.target.value);
            ev.target.value='';
            }
    }

The createTodo(ev) method is triggered when the ENTER key is pressed on the input field. It receives the event and from that we can get the value using ev.target.value. Then we tell Vue to emit an event named createTodo with the received value, so that components interested in this event could get the value sent. Once they register, when the event is emited their handler mapped to it will received it.

Return to the App.vue component and link the event emited to a handler inside the app component. Update the todos-input like this:

<todos-input :title="title" @createTodo="createTodoHandler" />    

In the script block of the App.vue add a methods block with the handler:

 ,
methods:{
createTodoHandler(todoTitle){
        if (todoTitle){
            this.todos.push({
                    id: this.todos.length +1,
                    title: todoTitle,
                    isCompleted: false
            })
        }
    }
} 

In the above method the handler will receive the todoTitle and if it is present then it will create a new todo item and add it to the todos list.

We have to add the todos array to have a place for holding the todos. Update the data() return object so that it contains a todos array populated with some data as fallows:

 ,
data() {
    return {
        title: "my todos",
        todos:[
                {id:1, title:"Taste JavaScript", isCompleted: true},
                {id:2, title:"Buy a unicorn", isCompleted: false},
                ]
    };
}

Now we have some todos and a way to store the new ones.

# III. Create the list component

It is time to display the list of todos inside the App.vue component using v-for directive. Let's add this to the end of the <ul class="todo-list"> :

 <li v-for="todo in todos" :key="todo.id" :class="{completed: todo.isCompleted}">
    <div class="view">
        <input class="toggle" type="checkbox" :checked="todo.isCompleted">
        <label> {{ todo.title }}</label>
        <button class="destroy"></button>
    </div>
    <input class="edit" value="Rule the web">
</li>

After adding the lines above and saving the App.vue you'll see the elements displayed on the page with the new entries.

The code above deserves some explanations. In order to add a class to an html tag we use :class="{completed: todo.isCompleted}" and it will add the class completed only if todo.isCompleted == true . In order to mark the checkbox as checked we use :checked= "todo.isCompleted" .

This code will add the checked to the element only if todo.isCompleted is true.

{{ todo.title }} will just display the text. It is time to delete all the li elements that are above the one we've just added. This way we'll see only our elements.

Clean up the code by moving the App.vue <section class="main"> inside the TodosList.vue in the template block. In the place where the section was removed add the todos-list element like this:

<todos-list />

Strange but nothing is displayed in the place where the list of todos was. We have to first add the todos propery to the TodosList.vue component and then we have to send the todos from the parent App.vue to the child TodosList.

Update the TodosList.vue component with the folowing props property:

name:"TodosList",
    props:{
        todos:{type:Array}
    }

Now let's send the todos from the parent to the child component. Update App.vue todos-list like this:

<todos-list :todos="todos" />

This line will send the todos array from the App component to the TodosList component. The list will expect the array of todos in the prop of type Array named todos.

There are 2 more things to do for the TodosList component. Enable the deletion of todos and complete the todo.

To enable deletion we have to $emit another event that will trigger the deletion of a Todo. To realize this add update the button with class destroy with a method call when it is clicked:

<button class="destroy" @click="destroy(todo)"></button>

The create the methods inside the script of the component:

,
methods:{
    destroy(todo){
        if (confirm("Are you sure you want to delete: " + todo.title))
            this.$emit('deleteTodo', todo);
        }
}

The confirm will ensure no deletion without confirmation.

First part is done now we have to remove the todo from the todos array of the App component.

Update the todos-list:

<todos-list :todos="todos" @deleteTodo="deleteTodoHandler" />

Add the new method inside the methods block of the component:

,
deleteTodoHandler(todo){
    this.todos.splice(this.todos.indexOf(todo),1);
}

Deletion is done let's add the completed part. This is done by updating the checkbox and adding a new method:

<input class="toggle" type="checkbox" :checked="todo.isCompleted" @click="changeTodo(todo)">

And the new method:

 ,changeTodo(todo){
            todo.isCompleted = !todo.isCompleted;
}

You can now play with the todos app to check if it works.

# Congratulations !!!

You made it !!!



This is the end of the coding session for this codelab!

Next let's do some deployments