Vue3 crud app with json-server and axios
Tags: vue, crud, axios, tailwindcss
Published: 2023-09-12 14:28:47

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](https://github.com/NeginSal/CRUD-Vue3)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q9cmthelg23kogllots8.png)

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
    }
  ]
}
```

---

## **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")
  }
];
```

**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>
```
**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>
```

**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>
```
**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('/')
    }
  },
}
```
**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>
```
**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>
```

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

Thank you for reading! 🍀