DEV Community

Cover image for learn vue js 3 basics by making todo-note application
abdallah
abdallah

Posted on

learn vue js 3 basics by making todo-note application

vue js become one of the most popular web user interface frameworks now, also one of the most loved frameworks because of its facility and its great ecosystem.

in this tutorial, we are going to take a look at vuejs basics and trying to give it a try by making a todo and note application with some cool features that are going to help you understand how to implement vue js in a project and enjoy it.

Before starting the tutorial let's take a look at the final product :
Alt Text of image
BTW I have no idea why I name it MODO, I think it looks like something on the rhyme of TODO, anyway let's go with the tutorial.

setup

let's start with CDN installation with the latest version :

<script src="https://unpkg.com/vue@3.0.5"></script>
Enter fullscreen mode Exit fullscreen mode

3.0.5 is the latest version now you can use another version instead it doesn't matter all had the same basics.
now to use this CDN create an HTML file that looks like this :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <script src="https://unpkg.com/vue@3.0.5"></script>
    <title>Modo</title>
</head>

<body>
        <div id="app">
             // from here any code start with template put it here 
        </div>

        <script>
             // and any code start with js put it here 
        </script>
</body>

</html>


Enter fullscreen mode Exit fullscreen mode

we gonna make our app inside the <div id="app"></div>.
so for now we can use vue in our project, it's that simple.

create and mount vue app :

js

const application ={
   our vue app
};
Vue.createApp(application).mount(#app)
Enter fullscreen mode Exit fullscreen mode

when we used CDN we have access to all vue builted-in properties like createApp and mount
createApp() this function does exactly what its name said, it's for vue app creation.
mount() this function takes the application written in js and implement it in HTML where the (queryselector) is.

now we had our app ready to use let's start with:

Add items inside a todo box

Template

<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item">
    <button>ADD</button><br>
</div>
Enter fullscreen mode Exit fullscreen mode

so this is a basic HTML where we have an input field and a button to submit data in this input when it's clicked.
so now we had 2 problems to solve using vue :

  • manipulate data between template and js
  • handle click events in vue we had something named v-model to use inside the template and something named data() to use inside js also, we have v-on or @ to handle events. let's use them to understand how they work. >template
<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item" v-model="taskInput">
    <button>ADD</button><br>
</div>
Enter fullscreen mode Exit fullscreen mode

js

const application ={
data(){
        return{
          taskInput : ""
      }
    }
 }
Enter fullscreen mode Exit fullscreen mode

what happened now?
we create a way for communication between template and application using a v-model and a variable returned with the data property
v-model go-to data and change its content depending on the item content so when we change the content inside the input field it will be changed in data property and vise-versa.

so now when we write something in the input field the data will be changed inside taskInput variable and now we need to save this data inside a list to show it in the tasks box, to do that we'll handle the click event of ADD button :

Template

<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item" v-model="taskInput">
    <button class="action-on" @click="addItem">ADD</button><br>

Enter fullscreen mode Exit fullscreen mode

js

const application ={data(){
        return{
          taskInput : "",
          tasks : [],
      }

    },
    methods:{
        addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput
            }
            this.tasks.push(newTask);
            this.taskInput=""
            }
}
Enter fullscreen mode Exit fullscreen mode

so what we do here is that we use @click (you can use v-on:click="addItem" instead of @click) to handle the click event to run the addItem method and inside the javascript, we define this method inside the methods:{} property where we define our methods to call, addItem make sure that the input field had a value and push this value to a list defined as tasks inside the data property then remove the content from the input field to be ready to refilled by another item(this here is for the components and give access to its data).

the traditional way to display items in any programming language is the for loop and vuejs also we had v-for so let's try it :

template

<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item" v-model="taskInput">
    <button class="action-on" @click="addItem">ADD</button><br>
    <div id="todos-box">
        <h2 class="titre">tasks box</h2>
-------------------------
        <ul id="list">
            <div v-for="task in tasks">
          <li>
               {{task.content}}
           </li>
            </div>
         </ul>

------------------
</div>

Enter fullscreen mode Exit fullscreen mode

so like we saw here we use v-for=" item in list" to loop in this list and we use the vue templating way to put js inside HTML using {{ }} like <h1>{{ 12+21 }}</h1> this return 33 inside the h1 (if I am good at calculation), so the output of this code will be an unordered list with all items inside it with li tag (*note that u can use the for loop in the li tag but I came from the future and saw that we need to separate them to add some buttons *).

Mark tasks as finished and delete them

to mark tasks as finished we need to add a 'finished' boolean property to the task object and a event listener for li tag to mark the task as finished when we click on it :

template

<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item" v-model="taskInput">
    <button class="action-on" @click="addItem">ADD</button><br>
    <div id="todos-box">
        <h2 class="titre">tasks box</h2>

        <ul id="list">
            <div v-for="task in tasks">
------------------------------------
          <li @click="markFinished(task)" 
              :class="{ex : task.finished}"
              >{{task.content}}
           </li>
---------------------------------------
            </div>
        </ul>
</div>
Enter fullscreen mode Exit fullscreen mode

so here we add a click listener to the markFinished method we'll look at it in the next code but the interesting thing here is :class="{something : if something}" first the ':' is short for v-bind: and this is how we use attribute dynamically from data like <a :href="URL"></a> and the URL will be defined in the data property, the binding attributes are very important for more dynamic websites.
so now the ex class is defined in the CSS to make the style of task line through to visually see what tasks are finished.

js

const app ={data(){
        return{
          taskInput : "",
          tasks : [],
    }

    },
    methods:{
        addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput,
----------------------------
                finished : false
---------------------------------

            }
            this.tasks.push(newTask)
            this.taskInput=""
            }
        },--------------
        markFinished(item){
            item.finished =! item.finished
        }
-------------------------------
}
Enter fullscreen mode Exit fullscreen mode

so here we saw that the markFinished just reverse the "finished" state for a specific task when it's clicked.

so let's add a button that removes finished tasks when clicked :

Template

<button id="remove" 
         @click="removeFinished">Remove Finished Tasks </button>

Enter fullscreen mode Exit fullscreen mode

js

methods:{
        addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput,
                finished : false,

            }
            this.tasks.push(newTask)
            this.taskInput=""
            }
        },
        markFinished(item){
            item.finished =! item.finished
        } ,
-------------------------------
        removeFinished(){
           let finished = this.tasks.filter(task => task.finished );
           finished.forEach(finishedTask => this.tasks.splice(this.tasks
            .findIndex(e => e.finished === finishedTask.finished),1))
        }
--------------------------------------}
Enter fullscreen mode Exit fullscreen mode

so the removeFinished() method filters the list and creates a finished list then for each one of them it finds the index of it then removes it.

Edit tasks and take notes on them

sometimes we need to edit our tasks because we change our minds about something or we write with spelling errors(like half of this blog post).
so to edit a task we'll use v-model that we explain before :

template

<input type="text" v-if="task.editingOn" v-model="task.content">
           <button class="action-on" @click="toggleEditing(task)">Edit</button>

Enter fullscreen mode Exit fullscreen mode

so here we use a new syntax:v-if
v-if shows up its element if the condition inside it is true, so the input field will show up if editiongOn is true and this is another property that we'll add to the task object so let's add it.

js

 methods:{
        addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput,
                finished : false,
---------------------------------
                editingOn : false,

            }

-------------------------------
        toggleEditing(item){
            item.editingOn =! item.editingOn ;

        }
---------------------------

Enter fullscreen mode Exit fullscreen mode

now when we click on the edit button an input field shows up to change the task content using v-model.

take notes on every task is very important to explain how to do it and we'll use another input field(text area) to save our notes .

template

<button class="action-on" @click="task.noteShowing=!task.noteShowing">Notes</button>

<div v-show="task.noteShowing">
            <div>
                <h2>take your notes here </h2>

                <textarea name="Notes" rows="4" cols="50" v-model="task.noteContent">
                    {{task.noteContent}}
                    </textarea>
            </div>
        </div>


Enter fullscreen mode Exit fullscreen mode

the last vue syntax to explain today is v-show
v-show is similar to v-if or let's say it's exactly the same but the difference is that v-show hide and shows the content using css not rendering so it's better for performance.

js

addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput,
                finished : false,
                editingOn : false,
----------------------------------
                noteShowing: false ,
                noteContent : ""
----------------------------------
            }
            this.tasks.push(newTask)
            this.taskInput=""
            }

Enter fullscreen mode Exit fullscreen mode

final code

so the final code we have now :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <script src="https://unpkg.com/vue@next"></script>
    <title>Modo</title>
</head>
<body>
    <!--title -->
    <h1 class="titre"></span> MO<span class="related">DO</span></h1>
    <!--end title-->
<div id="app">
    <input type="text" placeholder="add a todo item" id="add-item" v-model="taskInput">
    <button class="action-on" @click="addItem">ADD</button><br>
    <div id="todos-box">
        <h2 class="titre">tasks box</h2>
        <button id="remove" 
         @click="removeFinished">Remove Finished Tasks </button>
        <ul id="list">
            <div v-for="task in tasks">
          <li @click="markFinished(task)" 
              :class="{ex : task.finished}"
              >{{task.content}}
           </li>
           <input type="text" v-if="task.editingOn" v-model="task.content">
           <button class="action-on" @click="toggleEditing(task)">Edit</button>
           <button class="action-on" @click="task.noteShowing=!task.noteShowing">Notes</button>
         <!-- pop up notes -->
         <div v-show="task.noteShowing">
            <div>
                <h2>take your notes here </h2>

                <textarea name="Notes" rows="4" cols="50" v-model="task.noteContent">
{{task.noteContent}}
                    </textarea>
            </div>
        </div>
         <!--end popup-->
        </ul>

        </div>
    </div>
  </div>

    <script>
const app ={data(){
        return{
          taskInput : "",
          tasks : [],
    }

    },
    methods:{
        addItem(){
            if(this.taskInput!=""){
            newTask = {
                content : this.taskInput,
                finished : false,
                editingOn : false,
                noteShowing: false ,
                noteContent : ""
            }
            this.tasks.push(newTask)
            this.taskInput=""
            }
        },
        markFinished(item){
            item.finished =! item.finished
        } ,
        removeFinished(){
           let finished = this.tasks.filter(task => task.finished );
           finished.forEach(finishedTask => this.tasks.splice(this.tasks
            .findIndex(e => e.finished === finishedTask.finished),1))
        },
        toggleEditing(item){
            item.editingOn =! item.editingOn ;

        }

    }
}


Vue.createApp(app).mount("#app")

</script>

</body>
</html>


Enter fullscreen mode Exit fullscreen mode

you can create your own style for the application or download the full code from this link

it's my first time blogging so excuse everything you feel wrong in this blog post, hope you enjoy it .

Top comments (0)