In our previous Laravel Vue Js tutorial, we have explained how to build a to-do list app with Vue.js and Laravel. In this tutorial, we will explain how to make a CRUD(create, read, update, and delete) App with Laravel and Vue Js.
Vue JS is a popular and very user friendly JavaScript framework that helps to manage the application without page refresh page. We can easily use Vue with Laravel as it comes pre-packaged with Laravel. It used Laravel mix webpack tool to create Laravel application with Vue.
In this tutorial, we will cover following in our CRUD Application:
- Create Laravel Project
- Update MySQL Database Details
- Install Dependancies
- Create Migration, Model, and Controller
- Define Routes
- Create Vue App
- Create Vue App Component
- Define Route in Vue Router
- Add Vue.js dependencies to app.js
- Update Laravel Mix
- Compile Webpack
- Run Application
Now let’s get started!
1. Create Laravel Project
First we will create Laravel project and run below command to create Laravel proect laravel-vue-crud-app.
composer create-project laravel/laravel laravel-vue-crud-app
2. Update Database Details
After creating project, open .env file and update MySQL database details.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel-vue-crud DB_USERNAME=root DB_PASSWORD=
3. Install Dependancies
We will run the following command to install frontend dependencies:
npm install
We will also install vue, vue-router and vue-axiosmodules by running following command:
npm install vue vue-router vue-axios --save
4. Create Migration, Model, and Controller
We will run below command to create a Employee model, migration, and controller:
php artisan make:model Employee -mcr
We will open migration file of employee from database/migrations and replace code in up() function:
public function up() { Schema::create('employees', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->text('address'); $table->timestamps(); }); }
we will run below command to migrate the database:
php artisan migrate
we will open Employee.php model from app/Models and update with following code:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Employee extends Model { use HasFactory; protected $fillable = ['name','address']; }
we will open EmployeeController.php from app/Http/Controllers and update with following code to list, save, update, and delete methods:
<?php namespace App\Http\Controllers; use App\Models\Employee; use Illuminate\Http\Request; class EmployeeController extends Controller { public function index() { $categories = Employee::all(['id','name','address']); return response()->json($categories); } public function create() { // } public function store(Request $request) { $employee = Employee::create($request->post()); return response()->json([ 'message'=>'Employee Created Successfully!!', 'employee'=>$employee ]); } public function show(Employee $employee) { return response()->json($employee); } public function edit(Employee $employee) { // } public function update(Request $request, Employee $employee) { $employee->fill($request->post())->save(); return response()->json([ 'message'=>'Employee Updated Successfully!!', 'employee'=>$employee ]); } public function destroy(Employee $employee) { $employee->delete(); return response()->json([ 'message'=>'Employee Deleted Successfully!!' ]); } }
5. Define Routes In web.php
We will define routes for our application. We will open routes/web.php and routes/api.php from routes directory.
We will open routes/web.php and update with following code:
<?php use Illuminate\Support\Facades\Route; Route::get('{any}', function () { return view('app'); })->where('any', '.*');
We will open routes/api.php and update with following code:
<?php use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::middleware('auth:api')->get('/user', function (Request $request) { return $request->user(); }); Route::resource('employee',App\Http\Controllers\EmployeeController::class)->only(['index','store','show','update','destroy']);
6. Create Views File for Vue App
Now we wil go to the resources/views direcgory and create app.blade.php file for our Vue app data load.
<!doctype html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="csrf-token" value="{{ csrf_token() }}"/> <title>Laravel Vue Crud Application</title> <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet" type="text/css"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <link href="{{ mix('css/app.css') }}" type="text/css" rel="stylesheet"/> </head> <body> <div id="app"> </div> <script src="{{ mix('js/app.js') }}" type="text/javascript"></script> </body> </html>
7. Create Vue App Components
Now we will create componenets for Vue App. We will go to the resource/js and create components directory.
We will create main file of our Vue app App.vue in resource/js/components directory. We will define router-view in this file. We will update App.vue with following code:
<template> <main> <nav class="navbar navbar-expand-lg navbar-dark bg-success"> <div class="container-fluid"> <router-link to="/" class="navbar-brand" href="#">Laravel Vue Crud Application</router-link> <div class="collapse navbar-collapse"> <div class="navbar-nav"> <router-link exact-active-class="active" to="/" class="nav-item nav-link">Home</router-link> <router-link exact-active-class="active" to="/employee" class="nav-item nav-link">Employee</router-link> </div> </div> </div> </nav> <div class="container mt-5"> <router-view></router-view> </div> </main> </template> <script> export default {} </script>
We will create a directory employee in resource/js/components and create employee componenets vue files.
We will create Add.vue file in resource/js/components/employee and update with following code:
<template> <div class="row"> <div class="col-12"> <div class="card"> <div class="card-header"> <h4>Add Employee</h4> </div> <div class="card-body"> <form @submit.prevent="create"> <div class="row"> <div class="col-12 mb-2"> <div class="form-group"> <label>name</label> <input type="text" class="form-control" v-model="employee.name"> </div> </div> <div class="col-12 mb-2"> <div class="form-group"> <label>Address</label> <input type="text" class="form-control" v-model="employee.address"> </div> </div> <div class="col-12"> <button type="submit" class="btn btn-success">Save</button> </div> </div> </form> </div> </div> </div> </div> </template> <script> export default { name:"add-employee", data(){ return { employee:{ name:"", address:"" } } }, methods:{ async create(){ await this.axios.post('/api/employee',this.employee).then(response=>{ this.$router.push({name:"employeeList"}) }).catch(error=>{ console.log(error) }) } } } </script>
We will create Edit.vue file in resource/js/components/employee and update with following code:
<template> <div class="row"> <div class="col-12"> <div class="card"> <div class="card-header"> <h4>Update Employee</h4> </div> <div class="card-body"> <form @submit.prevent="update"> <div class="row"> <div class="col-12 mb-2"> <div class="form-group"> <label>Name</label> <input type="text" class="form-control" v-model="em.name"> </div> </div> <div class="col-12 mb-2"> <div class="form-group"> <label>Address</label> <input type="text" class="form-control" v-model="employee.address"> </div> </div> <div class="col-12"> <button type="submit" class="btn btn-success">Update</button> </div> </div> </form> </div> </div> </div> </div> </template> <script> export default { name:"update-employee", data(){ return { employee:{ name:"", address:"", _method:"patch" } } }, mounted(){ this.showEmployee() }, methods:{ async showEmployee(){ await this.axios.get(`/api/employee/${this.$route.params.id}`).then(response=>{ const { name, address } = response.data this.employee.name = name this.employee.address = address }).catch(error=>{ console.log(error) }) }, async update(){ await this.axios.post(`/api/employee/${this.$route.params.id}`,this.employee).then(response=>{ this.$router.push({name:"employeeList"}) }).catch(error=>{ console.log(error) }) } } } </script>
We will create List.vue file in resource/js/components/employee and update with following code:
<template> <div class="row"> <div class="col-12 mb-2 text-end"> <router-link :to='{name:"employeeAdd"}' class="btn btn-success">Create</router-link> </div> <div class="col-12"> <div class="card"> <div class="card-header"> <h4>Employee</h4> </div> <div class="card-body"> <div class="table-responsive"> <table class="table table-bordered"> <thead> <tr> <th>ID</th> <th>Name</th> <th>Address</th> <th>Actions</th> </tr> </thead> <tbody v-if="employees.length > 0"> <tr v-for="(employee,key) in employees" :key="key"> <td>{{ employee.id }}</td> <td>{{ employee.name }}</td> <td>{{ employee.address }}</td> <td> <router-link :to='{name:"employeeEdit",params:{id:employee.id}}' class="btn btn-success">Edit</router-link> <button type="button" @click="deleteEmployee(employee.id)" class="btn btn-danger">Delete</button> </td> </tr> </tbody> <tbody v-else> <tr> <td colspan="4" align="center">No employees Found.</td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </template> <script> export default { name:"employees", data(){ return { employees:[] } }, mounted(){ this.getEmployees() }, methods:{ async getEmployees(){ await this.axios.get('/api/employees').then(response=>{ this.employees = response.data }).catch(error=>{ console.log(error) this.employees = [] }) }, deleteEmployee(id){ if(confirm("Are you sure to delete this employee ?")){ this.axios.delete(`/api/employee/${id}`).then(response=>{ this.getEmployees() }).catch(error=>{ console.log(error) }) } } } } </script>
8. Add Routes in Vue Router
We will add routes for components in Vue Router for our app. The componenets will be loaded with lazy loading using Vue JS. We will open resources/js/routes.js and update with following code:
const EmployeeList = () => import('./components/employee/List.vue') const EmployeeCreate = () => import('./components/employee/Add.vue') const EmployeeEdit = () => import('./components/employee/Edit.vue') export const routes = [ { name: 'home', path: '/', component: EmployeeList }, { name: 'employeeList', path: '/employee', component: EmployeeList }, { name: 'employeeEdit', path: '/employee/:id/edit', component: EmployeeEdit }, { name: 'employeeAdd', path: '/employee/add', component: EmployeeCreate } ]
9. Import Vue.js Dependencies
We will import all required dependencies in our app. We will open resource/js/app.js file and import vue, routes, vue-axios and Bootstrap.
require('./bootstrap'); import vue from 'vue' window.Vue = vue; import App from './components/App.vue'; import VueRouter from 'vue-router'; import VueAxios from 'vue-axios'; import axios from 'axios'; import {routes} from './routes'; Vue.use(VueRouter); Vue.use(VueAxios, axios); const router = new VueRouter({ mode: 'history', routes: routes }); const app = new Vue({ el: '#app', router: router, render: h => h(App), });
10. Update Laravel Mix
We will also need to update webpack.mix.js with resources/js/app.js to compile js and css into public directory.
const mix = require('laravel-mix'); mix.js('resources/js/app.js', 'public/js') .postCss('resources/css/app.css', 'public/css', [ ]).vue();
11. Compile Webpack
After updating webpack.mix.js file, we will run below command to compile all JavaScript and CSS into application’s public directory:
npm run dev
We will also run below command to watch all relevant JavaScript and CSS files changes. It will automatically recompile when it detects a change to one of these files:
npm run watch
12. Run Application
Now, finally we will run our application by using below command:
php artisan serve
The application will be available on http://127.0.0.1:8000/