DEV Community

Cover image for Vue3 crud app with json-server and axios
Negin Saljooghi
Negin Saljooghi

Posted on

Vue3 crud app with json-server and axios

Hi, here we want to make a simple crud app with Vue.js by using json-server, axios and Tailwind CSS for styling.
In this app we have two fields: name, username with three default values that we can edit, delete them or add a new one.
You can find source code here: source code

Image description

let's start this project together step by step:


1. Setup project

Run vue create vue-crud-app to create a new app. Open the project and run npm run serve to see the project in your browser and then open a new terminal and run this command to start json-server :npx json-server --watch data/data.json --port 8000.


2. Files & Folder

we just need App.vue file and delete other files. Then create two folders: components & data.

Components :

In the src folder, create a components folder to put all of our files inside it. We have five components inside this folder :

AddUser.vue: to add a user.

EditUser.vue: to edit a user.

UserList.vue: to show all users.

Home.vue: it is our homepage,where we show UserList.vue & AddUser.vue components.

UserDetail.vue: to show user detail.

data:

It is in the root folder. Inside this folder create a file and called it data.json and put all of our data inside it.

{
  "users":[
    {
      "name":"Negin",
      "username":"negin007",
      "id":1
    },
    {
      "name":"Craig",
      "username":"benisphere",
      "id":2
    },
    {
      "name":"Ben",
      "username":"siliconeidolon",
      "id":3
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3.Code

router.js

  • src/router.js .
  • It is used to define and configure the router for our application & allowing you to navigate between different pages or components based on the URL.
const routes = [
  {
    path: "/",
    name: "users",
    component: () => import("./components/Home")
  },
  {
    path: "/user/:id",
    name: "editUser",
    component: () => import("./components/EditUser")
    // props: true
  },
  {
    path: "/addUser",
    name: "addUser",
    component: () => import("./components/AddUser")
  },
  {
    path: "/users/:id",
    name: "userDetail",
    component: () => import("./components/UserDetail")
  }
];
Enter fullscreen mode Exit fullscreen mode

App.vue

  • src/App.vue.
  • It has blockquote tag and <router-view/> to display the content of your different pages.
<template>
  <blockquote class="text-2xl font-semibold italic text-center text-blue-500 my-10">
    <span
      class="mx-2 before:block before:absolute before:-inset-1 before:-skew-y-3 before:bg-pink-400 relative inline-block">
      <span class="relative text-white "> CRUD App </span>
    </span>
    with Vue.js
  </blockquote>
  <router-view />
</template>

<script>
export default {};
</script>
Enter fullscreen mode Exit fullscreen mode

Home.vue

  • src/components/Home.vue.

  • It contains UserList and AddUser components.we fetch users here and then pass it as props to these components.

<template>
  <div class="max-w-xl pb-8 mx-auto px-5 bg-slate-100">
    <UserList :users="users" @userDeleted="handleUserDeleted" />
    <AddUser :users="users" />
  </div>
</template>

<script>
import UserList from "./UserList.vue";
import AddUser from "./AddUser.vue";
import axios from 'axios';

export default {
  components: {
    UserList,
    AddUser,
  },
  data() {
    return {
      users: []
    }
  },
  mounted() {
    this.fetchUsers();
  },
  methods: {
    fetchUsers() {
      axios
        .get('http://localhost:8000/users')
        .then((res) => { this.users = res.data })
        .catch(err => console.log(err))
    },
    handleUserDeleted(userId) {
      this.users = this.users.filter((user) => user.id !== userId);
    }
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

UserList

  • src/components/UserList.vue.
  • It shows list of users with two buttons for edit and delete each user.By click on name you can see user detail.
  • we have two methods:

deleteUser : for delete each user.
updateUser : for navigate to edit page and then edit name & username.

<template>
  <div v-if="users.length" class='py-5'>
    <div v-for="user in  users " :key="user.id" class='flex justify-between border-b-4'>
      <div class="flex ">
        <router-link :to="'/users/' + user.id">
          <p class='my-3 px-3'>{{ user.name }}</p>
        </router-link>
        <p class='my-3 px-3'>{{ user.username }}</p>
      </div>
      <div class="flex ">
        <p @click="updateUser(user.id)" class='mx-2 my-3 px-2 py-1 text-green-800
     hover:bg-green-400 hover:rounded-md hover:border hover:border-green-800'>EDIT</p>
        <p @click="deleteUser(user.id)" class='my-3 px-2 py-1 text-red-800 
     hover:bg-red-400 hover:rounded-md hover:border hover:border-red-800'>DELETE</p>
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import UserDetail from './UserDetail.vue';

export default {
  components: {
    UserDetail,
  },

  props: ['users'],
  methods: {
    deleteUser(id) {
      axios
        .delete(`http://localhost:8000/users/${id}`)
        .then(() => {
          this.$emit('userDeleted', id)
        })
        .catch((error) => { console.log(error) })
    },
    updateUser(id) {
      this.$router.push(`/user/${id}`)
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

EditUser

  • src/components/EditUser.vue.
  • We have two input fields for showing name & username.
  • Two methods for updating user and cancel editing and back to home page.
<template>
  <div class="flex items-center justify-center">
    <form @submit.prevent="handleSubmit">
      <div class='flex flex-col justify-center items-center bg-slate-100 p-10 mt-10 rounded-md'>
        <input v-model="name" class='my-2 px-5 py-1 rounded-full border border-gray-600' />
        <input v-model="username" class='my-2 px-5 py-1 rounded-full border border-gray-600' />
      </div>
      <div class="flex my-2 mx-20">
        <button class='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'>Update User</button>
        <button class='text-white mx-1 px-5 py-1 rounded-full bg-blue-500 hover:bg-blue-700'
          @click="backToHome">Cancel</button>
      </div>

    </form>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      id: this.$route.params.id,
      name: "",
      username: ""
    }
  },
  mounted() {
    axios
      .get('http://localhost:8000/users/' + this.id)
      .then((user) => {
        this.name = user.data.name;
        this.username = user.data.username;
      })
  },
  methods: {
    handleSubmit() {
      axios
        .put('http://localhost:8000/users/' + this.id, {
          name: this.name,
          username: this.username,
        })
        .then(() => {
          this.$router.push("/");
        })
    },
    backToHome() {
      this.$router.push('/')
    }
  },
}
Enter fullscreen mode Exit fullscreen mode

UserDetail

  • src/components/UserDetail.vue.
  • To see user detail,here: name & username.
<template>
  <div class="max-w-xl pb-8 mx-auto px-5 bg-slate-100">
    <div class="flex flex-col text-center py-5 ">
      <p class='px-3 py-3 border-b-4'>Name : {{ user ? user.name : '' }}</p>
      <p class='px-3 py-3'>UserName : {{ user ? user.username : '' }}</p>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: null,
      id: this.$route.params.id
    }
  },
  mounted() {
    this.fetchUser();
  },
  methods: {
    fetchUser() {
      axios
        .get('http://localhost:8000/users/' + this.id)
        .then((res) => { this.user = res.data })
        .catch(err => console.log(err))
    }
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

AddUser

  • src/components/AddUser.vue.
  • It has two fields for add name and username & a handleSubmit method to add user to list of users.
<template>
  <form @submit.prevent="handleSubmit">
    <div class='flex flex-col justify-center items-center '>
      <div class='mb-2'>
        <input class='px-3 py-1 rounded-full border border-gray-600' v-model="name" placeholder="Name" />
      </div>
      <div class='mb-2'>
        <input class='px-3 py-1 rounded-full border border-gray-600' v-model="username" placeholder="UserName" />
      </div>
      <div class='mb-2'>
        <button class="bg-blue-500 hover:bg-blue-700 text-white py-1 px-3 rounded-full">
          Add
        </button>
      </div>
    </div>
  </form>
</template>

<script>
import axios from 'axios';

export default {
  props: ['users'],
  data() {
    return {
      name: '',
      username: ''
    }
  },
  methods: {
    handleSubmit() {
      axios
        .post("http://localhost:8000/users", {
          name: this.name,
          username: this.username,
        })
        .then((response) => {
          const data = response.data;
          this.users.push(data);
          this.name = "";
          this.username = "";
        });
    },
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

Now here we go! We created a simple crud app with Vue.js, json-server, axios and Tailwind CSS.

Thank you for reading! 🍀

Top comments (0)