LaravelVue js

Crud App with Laravel and Vue – Single Page Application

In this blog we will learn about how we can create a single page application with a crup app with laravel and Vue Js.

In this crup app with laravel and Vue Js, you will learn how to implement laravel vue js crud (create, read, update and delete) spa application with vue js router and laravel framework.

Crud App with Laravel and Vue (SPA) Example

To create this application I am going to use Laravel 8 and Vue js 2.5, Follow the following steps to create the Crud App with Laravel and Vue.

  • Download Laravel Application
  • Configure your env for database connection
  • Install Npm Dependencies
  • Create Migration, Model and Controller
  • Defininig Routes In Api.php
  • Create Vue Js Components For Crud App
  • Define Vue Js Routes For Crud App
  • Include Vue Js Dependencies to app.js
  • Run Development Server

Step-1: Download the Laravel Application

Open your command prompt under your htdocs and run the below command

composer create-project laravel/laravel laravel-vue-crud

Step-2: Configure you .env file for database connection

 DB_CONNECTION=mysql
 DB_HOST=127.0.0.1
 DB_PORT=3306
 DB_DATABASE=learn_vue_crud
 DB_USERNAME=root
 DB_PASSWORD=

Step-3: Install Npm Dependencies

Run the following command to install Node

npm i

After that you have to install vue-router and vue-axios. vue-axios will be used for calling Laravel API. Run the following command on your command prompt:

npm install vue-router vue-axios --save

After installing all dependencies run this command:

npm run watch

npm run watch is used during the development mode, it will listen all the file changes and compile your assests, npm run prod command will be used during the production mode and it can’t listen the changes everytime.

I suggest you to when all the changes done, then before the deployment run the npm run prod command.

Step 4: Create Migration, Model, and Controller

To create migration, model and, controller run the below command

php artisan make:model Book -mcr

Now go to database->migrations and open the file create_books_table.php, you can the file name will be like this 2020_11_21_124216_create_books_table.php, just open that file and put the below code

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id(); // auto increment 
            $table->timestamps();  // for created_at and updated_at
            $table->string('name'); // creates a name column
            $table->string('author'); // creates a author column
        });

    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('books'); // drops the table
    }
}

Now it’s time to create tables in database using the migration command just run the below command

php artisan migrate

It will create the tables in your database like the below image

laravel-vue-migration-table
laravel vue migration table

When click on books you can see the below tables

laravel-vue-migration-table

Now go to app->Models and open Book.php file and enter the following code

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;

    protected $guarded = []; // All fields inside the $guarded array are not mass-assignable  
}

If you are familiar with laravel then you see, in some blog people uses guarded and some use fillable below is the basic difference between them.

In Laravel, fillable attributes are used to specify those fields which are to be mass assigned. Guarded attributes are used to specify those fields which are not mass assignable.

Now we will write code in the controller, so go the app->Http->Controllers here you can see a file named BookController.php

<?php

namespace App\Http\Controllers;

use App\Models\Book; 
use Illuminate\Http\Request;

class BookController extends Controller
{
    public function index()
    {   
        $books = Book::all()->toArray(); // get all data from database
        return array_reverse($books); // convert the data in json
    }

    // add book
    public function add(Request $request)
    {
        $book = new Book([
            'name' => $request->input('name'),
            'author' => $request->input('author')
        ]);
        $book->save(); // save Data in database

        return response()->json('The book successfully added');  // send response with a message
    }

    // edit book
    public function edit($id)
    {
        $book = Book::find($id); // find column with the given id

        return response()->json($book); // return all those data
    }

    // update book
    public function update($id, Request $request)
    {
        $book = Book::find($id); // find column with the given id

        $book->update($request->all()); // update that field relatd to the Id.

        return response()->json('The book successfully updated'); // send response with a message
    }

    // delete book
    public function delete($id)
    {
        $book = Book::find($id); // find column with the given id

        $book->delete(); // delete that column

        return response()->json('The book successfully deleted'); // send response with a message
    }
}

Step-5: Defining routes in web.php

Now define routes in the api.php routes file. So Go to the Routes folder and Open the api.php file and update the following routes:

Route::get('books', [BookController::Class,'index']);
Route::group(['prefix' => 'book'], function () {
    Route::post('add', [BookController::Class,'add']);
    Route::get('edit/{id}', [BookController::Class,'edit']);
    Route::post('update/{id}', [BookController::Class,'update']);
    Route::delete('delete/{id}', [BookController::Class,'delete']);
});

Don’t forget to add controller namespace on the top of api.php
after adding the below one the full code will look like below

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\BookController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Route::get('books', [BookController::Class,'index']);
Route::group(['prefix' => 'book'], function () {
    Route::post('add', [BookController::Class,'add']);
    Route::get('edit/{id}', [BookController::Class,'edit']);
    Route::post('update/{id}', [BookController::Class,'update']);
    Route::delete('delete/{id}', [BookController::Class,'delete']);
});

Step 6: Create Vue Js App

In this step, navigate to resources/views and open app.blade.php file and add the below code

<!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>Crud with laravel and Vue</title>
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet" type="text/css">
    <link href="{{ mix('css/app.css') }}" type="text/css" rel="stylesheet"/>
    <style>
        .bg-light {
            background-color: #eae9e9 !important;
        }
    </style>
</head>
<body>
<div id="app">
</div>
<script src="{{ mix('js/app.js') }}" type="text/javascript"></script>
</body>
</html>

Step 7: Create Vue Js Components For Crud App

Now go to resources->js->components create following vue components

  • App.vue
  • AddBook.vue
  • AllBooks.vue
  • EditBook.vue

Now open App.Vue and add the following code

<template>
    <div class="container">
        <div class="text-center" style="margin: 20px 0px 20px 0px;">
            <span class="text-secondary">Crud Application With Laravel and Vue Js</span>
        </div>
        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <div class="collapse navbar-collapse">
                <div class="navbar-nav">
                    <router-link to="/" class="nav-item nav-link">Home</router-link>
                    <router-link to="/add" class="nav-item nav-link">Add Book</router-link>
                </div>
            </div>
        </nav>
        <br/>
        <router-view></router-view>
    </div>
</template>

<script>
    export default {}
</script>

Note that, App.vue is the main Vue file. We will define router- view in the file. So all route pages will be shown in the App.vue file

Now open AddBook.vue and the below code

<template>
    <div>
        <h3 class="text-center">Add Book</h3>
        <div class="row">
            <div class="col-md-6">
                <form @submit.prevent="addBook">
                    <div class="form-group">
                        <label>Name</label>
                        <input type="text" class="form-control" v-model="book.name">
                    </div>
                    <div class="form-group">
                        <label>Author</label>
                        <input type="text" class="form-control" v-model="book.author">
                    </div>
                    <button type="submit" class="btn btn-primary">Add Book</button>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                book: {}
            }
        },
        methods: {
            addBook() {
                let uri = 'api/book/add'; // add book api
                this.axios
                    .post(uri, this.book) // sending the data to the controller
                    .then(response => (
                        this.$router.push({name: 'home'}) // return back to the homepage
                    ))
                    .catch(error => console.log(error))
                    .finally(() => this.loading = false)
            }
        }
    }
</script>

Now go to AllBooks.vue and add the below code

<template>
    <div>
        <h3 class="text-center">All Books</h3><br/>

        <table class="table table-bordered">
            <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>Author</th>
                <th>Created At</th>
                <th>Updated At</th>
                <th>Actions</th>
            </tr>
            </thead>
            <tbody>
            <tr v-for="book in books" :key="book.id">
                <td>{{ book.id }}</td>
                <td>{{ book.name }}</td>
                <td>{{ book.author }}</td>
                <td>{{ book.created_at }}</td>
                <td>{{ book.updated_at }}</td>
                <td>
                    <div class="btn-group" role="group">
                        <router-link :to="{name: 'edit', params: { id: book.id }}" class="btn btn-primary">Edit
                        </router-link>
                        <button class="btn btn-danger" @click="deleteBook(book.id)">Delete</button>
                    </div>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                books: []
            }
        },
        created() {
            this.axios 
                .get('api/books')
                .then(response => {
                    this.books = response.data;
                });
        },
        methods: {
            deleteBook(id) {
                this.axios
                    .delete(`api/book/delete/${id}`)
                    .then(response => {
                        let i = this.books.map(item => item.id).indexOf(id); // find index of your object
                        this.books.splice(i, 1)
                    });
            }
        }
    }
</script>

Now go to EditBook.vue and add the following code

<template>
    <div>
        <h3 class="text-center">Edit Book</h3>
        <div class="row">
            <div class="col-md-6">
                <form @submit.prevent="updateBook">
                    <div class="form-group">
                        <label>Name</label>
                        <input type="text" class="form-control" v-model="book.name">
                    </div>
                    <div class="form-group">
                        <label>Author</label>
                        <input type="text" class="form-control" v-model="book.author">
                    </div>
                    <button type="submit" class="btn btn-primary">Update Book</button>
                </form>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                book: {}
            }
        },
        created() {
            this.axios
                .get(`api/book/edit/${this.$route.params.id}`)
                .then((response) => {
                    this.book = response.data;
                });
        },
        methods: {
            updateBook() {
                this.axios
                    .post(`api/book/update/${this.$route.params.id}`, this.book)
                    .then((response) => {
                        this.$router.push({name: 'home'});
                    });
            }
        }
    }
</script>

Step 8: Define Vue Js Routes For Crud App

Now, you need to define vue routes. So go to resources>js folder, create a file named routes.js and update the following routes into your routes.js file

export const routes = [
    {
        name: 'home',
        path: '/',
        component: () => import('./components/AllBooks.vue'),
    },
    {
        name: 'add',
        path: '/add',
        component: () => import('./components/AddBook.vue'),
        
    },
    {
        name: 'edit',
        path: '/edit/:id',
        component: () => import('./components/EditBook.vue'),
    }
];

Step 9: Include Vue Js Dependencies to app.js

require('./bootstrap');
window.Vue = require('vue');

import App from './App.vue';
import VueRouter from 'vue-router';
import axios from 'axios';
import {routes} from './routes';

Vue.use(VueRouter);
Vue.prototype.axios = axios;

const router = new VueRouter({
  mode: 'history',
  routes: routes
})

const app = new Vue({
  el: '#app',
  router: router,
  render: h => h(App),
});

Step 10: Run Development Server

Run the below command to compile your assests

npm run watch

Run the below command to run laravel application in development server

php artisan serve

Now open your browser and open this url http://localhost:8000/

you will see the below site in your browser

vue-laravel-crud

Shaiv Roy

Hy Myself shaiv roy, I am a passionate blogger and love to share ideas among people, I am having good experience with laravel, vue js, react, flutter and doing website and app development work from last 7 years.

Related Articles

4 Comments

  1. Hi, the update function in the editbook seems to not work, because it calls for the edit/api/updates/3, how can I fix this?

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button