Vue.js TODO CRUD App Using Vuex State Management Library and JSONPlaceolder Rest API Full Project For Beginners in 2020

Vue.js TODO CRUD App Using Vuex State Management Library and JSONPlaceolder Rest API Full Project For Beginners in 2020
  • Post author:
  • Post category:Vue
  • Post comments:0 Comments

 

Welcome folks today in this tutorial we will be using Vuex State Management Library in Vue.js to Make a simple Todo CRUD App from scratch. This will be a tutorial for pure beginners which are very new to Vuex as a library to manage state or data inside Vue Applications. For this application we will be using JSONPlaceholder Fake REST API. A step by step youtube video is also shown below.

 

 

 

LIVE DEMO

 

 

Advantages of Vuex

 

  1. Vuex is a lightweight and easy to understand state management library similiar to redux which is used in React applications
  2. It is helpful in scenarios where you have multiple components or modules running at the same time and you want to manage your state or data effectively without compromising the application.

 

Installation

 

First of all you will create your brand new vue.js project at the command line with the help of this command shown below

 

vue create testproject

 

Now we will install the vuex library inside our project like this

 

 

 

 

 

Now we need to open our App.vue file and write down the following code into it we will be creating three components namely AddTodo and Todos and FilterTods components to add a Todo and display all Todos and filter todos to only display a certain number of todos in application respectively.

 

App.vue

 

<template>
  <div id="app">
    <AddTodo />
    <FilterTodos/>
    <Todos />
  </div>
</template>

<script>
import AddTodo from './components/AddTodo.vue'
import Todos from './components/Todos.vue'
import FilterTodos from './components/FilterTodos.vue'

export default {
  name: 'App',
  components: {
    AddTodo,
    Todos,
    FilterTodos
  }
}
</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>

 

 

Now inside our components folder you need to create these components like this as shown in the figure

 

 

 

Todos.vue

 

<template>
    <div>
        <div>
            <h1>Todos</h1>
        </div>
    </div>
</template>

<script>
export default {
    name:"Todos"
}
</script>

<style scoped>

</style>

 

 

AddTodo.vue

 

<template>
    <div>
        <div>
            <h1>AddTodo</h1>
        </div>
    </div>
</template>

<script>
export default {
    name:"AddTodo"
}
</script>

<style scoped>

</style>

 

 

FilterTodos.vue

 

<template>
    <div>
    <div>
        <h1>FilterTodos</h1>
    </div>
    </div>
</template>

<script>
export default {
    name:"FilterTodos"
}
</script>

<style scoped>

</style>

 

 

If you now run your vue.js server by executing the following commad given below

 

npm run serve

 

You will see the following output as shown below

 

 

 

Configuring Vuex Library

 

Now we will configure the Vuex library inside Vue application. So now first of all go to src directory of your project  and make a new folder store inside it as show below

 

 

 

Now make another file inside the store folder called as index.js which will import the Vue and Vuex library like this as shown below

 

 

 

store/index.js

 

// Entrypoint for vuex

import Vuex from 'vuex';
import Vue from 'vue';
import todos from './modules/todos';

// Load vuex
Vue.use(Vuex);

// Create store
export default new Vuex.Store({
  modules: {
    todos
  }
});

 

 

In this block of code we are importing a module called as todos from the modules folder which we haven’t created. We will create this modules folder and inside it we will create this todos module later. So after it we are invoking the Storemethod of Vuex library to import this todos module.

 

 

Registering Vuex to Vue App

 

Now to register this Vuex library we need to go to the main.js file of the Vue Application and copy paste the following code into it

 

 

 

main.js

 

 

import Vue from 'vue';
import App from './App.vue';
import store from './store';

Vue.config.productionTip = false

new Vue({
  store,
  render: h => h(App),
}).$mount('#app')

 

 

Here we are just importing the store file inside this file and passing this store to the Vue main constructor.

 

Now we need to create the modules folder inside the store folder that we have created earlier like this

 

 

 

So we have created a file todos.js inside the modules folder. Inside this file we will write all the code regarding our state and vuex

 

Installing Axios

 

For this application we will making a HTTP requests to JSONPLACEHOLDER API to get our todos update our todos and also remove the todos so for that we need to use this library. Go to command prompt and execute the command given below

See also  Vue.js Materialize CSS Font Awesome Icon Picker in Browser Using Javascript Full Project For Beginners

 

npm install --save axios

 

 

Main Components of Vuex

 

Largely there are four main components of Vuex where the whole library concept revolves. These are as follows

  1.  State : This is the actual state or data that you define inside your application
  2. Getter: This is the second component which is responsible for getting the value of the state or getting the data of the application at any time. You can call getter function to get the state of the application
  3. Action: Action from the name itself takes the appropriate action towards the state of the application for example manipulate or change the value of the state by some business logic of the application and then it contains a special argument inside it’s function called as commit which we need to call when we are done changing the value. This commit will execute lastly to call mutation.
  4. Mutation: Mutation is actually responsible for actually taking the modified state or data from action through commit and actually changing the original state of the application.

 

So now inside your todos.js we will define the state and action and getter and mutation like this.

 

import axios from 'axios';

const state = {
  todos: []
};

const getters = {
  allTodos: (state) => {
    return state.todos
  }
};

const actions = {
  async fetchTodos({ commit }) {
    const response = await axios.get('https://jsonplaceholder.typicode.com/todos');

    commit('setTodos', response.data);
  }
}

const mutations = {
    setTodos: (state, todos) => (state.todos = todos)
};


export default {
    state,
    getters,
    actions,
    mutations
};

 

 

Here there are three methods are there of getter,action and mutation namely getAllTodos and fetchTodos and setTodos respectively.

 

And we have defined a single property in the state called a empty array of todos. And also inside the action method fetchTodos we are using axios to make a http request to JSONPLACEHOLDER API to return all todos and then setting the result to the todos array and passing those changes to commit ultimately calling mutation function setTodos to change the original state of the todos.

Lastly we are exporting all these methods by using the export keyword so that we can use these methods inside our application.

 

Now go to your Todos.vue component and we will be using these functions to render out all the todos which will be coming from the api

 

Todos.vue

 

<template>
  <div>
    <div>
      <h1>Todos</h1>
      <div class="todos">
        <div
          v-for="todo in allTodos"
          class="todo"
          v-bind:key="todo.key"
        >
          {{ todo.title }}
        </div>
      </div>
    </div>
  </div>
</template>

 

<script>
import { mapGetters, mapActions } from 'vuex';
export default {
  name: "Todos",
  methods:{
      ...mapActions(["fetchTodos"])
  },
  computed: mapGetters(["allTodos"]),
  created() {
    this.fetchTodos();
  }
};
</script>

 

First of all we have imported the methods mapGetters and mapActions which are library methods using destructuring from vuex and then we have called these inside the methods section. We are using the computed property to get the state or data in this case the array of todos. And also there is a special function inside every component in Vue which is created() which will automatically be called once the component is created and inside it we are calling the fetchTodos fuction to get all the todos and set the state of todos array to the result.

And then inside the template we are using v-for directive to loop through the array displaying all todos also passing the id which will be unique through key parameter and then inside it printing the title of the todo.

If you run the app your todos will be there like this as shown below.

 

 

 

We can add some styles to it so copy paste the css code inside the style tags like this

 

<style scoped>
  .todos {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 1rem;
  }
  .todo {
    border: 1px solid #ccc;
    background: #41b883;
    padding: 1rem;
    border-radius: 5px;
    text-align: center;
    position: relative;
    cursor: pointer;
  }
  i {
    position: absolute;
    bottom: 10px;
    right: 10px;
    color: #fff;
    cursor: pointer;
  }
  .legend {
    display: flex;
    justify-content: space-around;
    margin-bottom: 1rem;
  }
  .complete-box,
  .incomplete-box {
    display: inline-block;
    width: 10px;
    height: 10px;
  }
  .complete-box {
    background: #35495e;
  }
  .incomplete-box {
    background: #41b883;
  }
  .is-complete {
    color: #fff;
    background: #35495e;
  }
  @media (max-width: 500px) {
    .todos {
      grid-template-columns: 1fr;
    }
  }
</style>

 

 

 

 

Deleting Todos

 

Now we will be deleting Todos using a delete button which will be present on each todo which is rendered. Now inside the todos.vue you need to add this delete icon in the template of the component

See also  Vue.js Lazy Loading Images From API in Grid View Using vue-lazyload Library Example in Javascript Full Project For Beginners

 

<div
          v-for="todo in allTodos"
          class="todo"
          v-bind:key="todo.key"
        >
          {{ todo.title }}
          <i class="fas fa-trash-alt" v-on:click="deleteTodo(todo.id)"></i>
        </div>

 

Here we are using fontawesome library so you need to include the cdn of fontawesome inside your public/index.html file like this

 

<script src="https://kit.fontawesome.com/dfc3b70b57.js" crossorigin="anonymous"></script>

 

Now if you open the application you will see the following output like this

 

 

 

So we have defined a custom function on this fontawesome icon by the help of vue directive v-on:click . We will define this deleteTodo function inside the script section like this

 

 

 

After defining this method inside this array we need to define this method inside our module file which is todos.js

 

todos.js

 

const actions = {

 async deleteTodo({ commit }, id) {
    await axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`);

    commit('removeTodo', id);
  }


}

 

 

const mutations = {

removeTodo:(state,id) => state.todos = state.todos.filter((todo) => todo.id !== id)

}

 

 

So now if you click on the dustbin icon on the todo that todo will be deleted from the todos array inside the application.

 

Updating Todos

 

Now we will be adding a dynamic class on the todo once we double click on the todo. Through this we will be updating the todo.

 

Now go to Todos.vue file and change the template as this

 

<template>
  <div>
    <h3>Todos</h3>
    <div class="legend">
      <span>Double click to mark as complete</span>
      <span>
        <span class="incomplete-box"></span> = Incomplete
      </span>
      <span>
        <span class="complete-box"></span> = Complete
      </span>
    </div>
    <div class="todos">
      <div
        @dblclick="onDblClick(todo)"
        :key="todo.id"
        v-for="todo in allTodos"
        class="todo"
        v-bind:class="{'is-complete':todo.completed}"
      >
        {{ todo.title }}
        <i class="fas fa-trash-alt" v-on:click="deleteTodo(todo.id)"></i>
      </div>
    </div>
  </div>
</template>

 

 

 

 

Now as you can see when we load todos from the api the completed values for the todos are random some are true and some are false and depending on that value we are toggling the class that we have provided to the todo through v-bind:class directive

Also we have binded a double click directive on the todo through @dblclick and we have binded a custom method and passing the id of the todo which was clicked.

So now we will define this function in the next step

 

<script>
import { mapGetters, mapActions } from 'vuex';
export default {
  name: "Todos",
  methods:{
      ...mapActions(["fetchTodos","deleteTodo","updateTodo"]),
      onDblClick(todo) {
      const updatedTodo = {
        id: todo.id,
        title: todo.title,
        completed: !todo.completed
      }
      this.updateTodo(updatedTodo);
    }
  },
  computed: mapGetters(["allTodos"]),
  created() {
    this.fetchTodos();
  }
};
</script>

 

 

So now inside this method we are constructing a new todo passing all the three properties id of the todo title of the todo and also the completed value inside this we are toggling this value. Let’s say the value is true we are changing to false and vice versa. After that we are calling another method which will actually update the data for us which is updateTodo now we have also added this method inside the array as you can see.

Now we need to simply define this method inside the todos.js file

 

const actions = {


 async updateTodo({ commit }, updatedTodo) {
    const response = await axios.put(`https://jsonplaceholder.typicode.com/todos/${updatedTodo.id}`, updatedTodo);

    commit('updateTodo', response.data);
  }

}

 

const mutations = {

 updateTodo: (state, updatedTodo) => {
        // Find index
        const index = state.todos.findIndex(todo => todo.id === updatedTodo.id);
    
        if (index !== -1) {
          state.todos.splice(index, 1, updatedTodo);
        }
    }

}

 

 

So now in this case we are making a put request to api and then the updated result is returned and after that we are passing that result to the mutation function to modify the state or update the state. For updating the state we are using the splice method of javascript.

So now if you double click the todo color will change from green to blue

 

Adding Todos

 

Lastly we take the operation of adding todos inside our array through a simple form. So go to AddTodo.vue component and copy paste the following code

 

<template>
  <div>
    <h3>Add Todo</h3>
    <div class="add">
      <form @submit="onSubmit">
        <input type="text" v-model="title" placeholder="Add Todo" />
        <input type="submit" value="Submit">
      </form>
    </div>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  name: "AddTodo",
  data() {
    return {
      title: ''
    }
  },
  methods: {
    ...mapActions(["addTodo"]),
    onSubmit(event) {
      event.preventDefault();
      this.addTodo(this.title);

      this.title = '';
    }
  }
}
</script>

<style scoped>
  form {
    display: flex;
  }

  input[type="text"] {
    flex: 10;
    padding: 10px;
    border: 1px solid #41b883;
    outline: 0;
  }

  input[type="submit"] {
    flex: 2;
    background: #41b883;
    color: #fff;
    border: 1px solid #41b883;
    cursor: pointer;
  }
</style>

 

See also  Build Anonymous Random P2P WebRTC Zoom Clone Video Chat in Mobile Using Node.js Socket.io & Vue.js in Javascript Full Project For Beginners

 

 

 

So this is a fairly simple component inside the template we have a simple form and also we have attached a submit directive of Vue when the form submits we are calling a custom function and inside the fields we have a single field for the title of the todo and then the submit button. We have provided some custom styling to the form.

Now in the script section we are again importing all the method of vuex and then calling the method addTodo

So we need to go to the todos.js file and define this method like this

 

const actions = {

async addTodo({commit},title){
      const response = await axios.post(`https://jsonplaceholder.typicode.com/todos`,
      {title:title,completed:false})

      commit('addTodo',response.data)
  }

}

 

 

const mutations = {

addTodo:(state,newTodo) => state.todos.unshift(newTodo)


}

 

 

So now if you go to the form submit a title and enter you will see your todo appeared on the screen

 

Filtering Todos on Length

 

Now lastly we only want to display x number of todos inside our application through the api. For this you need to open your FilterTodos.vue file and copy paste the following code which is given below.

 

<template>
  <div>
    Filter Todos:
    <select v-on:change="filterTodos($event)">
      <option value="200">200</option>
      <option value="100">100</option>
      <option value="50">50</option>
      <option value="20">20</option>
      <option value="10">10</option>
      <option value="5">5</option>
    </select>
  </div>
</template>

<script>
import { mapActions } from 'vuex';

export default {
  name: "FilterTodos",
  methods: {
    ...mapActions(["filterTodos"])
  }
}
</script>

<style scoped>
  select {
    margin-top: 20px;
    padding: 6px;
    border: 1px solid #41b883;
  }
</style>

 

 

 

 

As you can see we have a simple select box where we can select how many todos we want to display on the application. For this select box inside the template we have binded a directive of Vue to get the value of the select box when it is changed and also we have defined a custom function and we have passed this function to our todos.js file. Now we will go to this file and define this function like this

 

const actions = {

 async filterTodos({ commit }, event) {
    // Get the limit
    const limit = parseInt(event.target.options[event.target.options.selectedIndex].innerText);
    
    // Request
    const response = await axios.get(`https://jsonplaceholder.typicode.com/todos?_limit=${limit}`);

    commit('setTodos', response.data);
  },

}

 

 

 

 

Now you can see we have selected 10 todos in the select box and only 10 todos are displayed and fetched from the rest api.

 

This was the application guys. Hope you like it please share this post with your friends. The github repo of this project is given below.

 

 

DOWNLOAD SOURCE CODE

 

 

Live Demo

 

 

Leave a Reply