How to Create Laravel with Vue CRUD Application

Here is the step-by-step guide to using Vue with Laravel

Step 1: Creating a Laravel project

Type the following command in your terminal.

composer create-project laravel/laravel laravelvuejstutorial --prefer-dist

After installing the project, go to the folder and type the following command in your terminal again.

npm install

It will install all the JavaScript dependencies regarding VueJS.

In addition, it will install laravel-mix, which you can think of as a kind of module bundle like webpack.

Now, set up a database in MySQL, and we need to configure it in Laravel. So in your project root, there is a .env file; in that file, you need to configure your username, DB name, and password.

After configuring, type the following command in your terminal.

php artisan migrate

If you navigate to resources  >> assets  >>  js  >>  components, you will see the Example.vue component is there, so basically, Laravel provides VueJS support out of the box.

However, we can use other JS frameworks like React or Angular. This component is required in the external JS file called app.js. Laravel Mix will compile this file. 

I have removed the comments provided by Laravel so that the app.js file will look like this.

// app.js

require('./bootstrap');

window.Vue = require('vue');

Vue.component('example', require('./components/Example.vue'));

const app = new Vue({
 el: '#app'
});

We need to install some other dependencies to run the Vue library smoothly, and also we need to use vue-router for routing our application.

npm install --save-dev vue-axios vue-loader vue-router vue-template-compiler 

Step 2: Edit the default configuration.

We are going to change this file by the following code.

// app.js

import Vue from 'vue';

import VueRouter from 'vue-router';
Vue.use(VueRouter);

import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);

const router = new VueRouter({ mode: 'history'});
new Vue(Vue.util.extend({ router })).$mount('#app');

We have imported vue, vue-router, vue-axios, and axios libraries for our application.

Created the router object and set the mode history to eliminate the pound (#) on every route.

Switch to resources  >>  views  >>  welcome.blade.php file and replace the following code with that file.

// welcome.blade.php

<!doctype html>
<html lang="{{ app()->getLocale() }}">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Laravel Vue CRUD Application</title>
        <link href="{{asset('css/app.css')}}" rel="stylesheet" type="text/css">
    </head>
    <body>
        <div id="app">
        </div>
         <script>
           window.Laravel = <?php echo json_encode([
               'csrfToken' => csrf_token(),
                    ]); ?>
          </script>
        <script src="{{asset('js/app.js')}}"></script>
    </body>
</html>

We need to create one Vue component inside resources  >>  assets  >>  js directory and call this component an App.vue.

// App.vue

<template>
    <div class="container">
        <div>
            <transition name="fade">
                <router-view></router-view>
            </transition>
        </div>
    </div>
</template>

<style>
    .fade-enter-active, .fade-leave-active {
      transition: opacity .5s
    }
    .fade-enter, .fade-leave-active {
      opacity: 0
    }
</style>

<script>

    export default{
    }
</script>

This component will work as a container of our application when the routes of our Vue application change.

According to that, different components will be rendered within the <router-view><router-view> tag.

We need to include this component in our app.js file and pass it to the Vue object while creating an instance.

// app.js

import App from './App.vue';

new Vue(Vue.util.extend({ router }, App)).$mount('#app');

Go to the terminal and type the following command.

npm run watch

If you see any error, please first check if there is a dependency that needs to be installed in the first place.

Step 3: Create routes with vue-router for our application.

In the app.js file, we also include the Example.vue component because we will create routes for our application. So, first, create an array of routes in the app.js file.

// app.js

const routes = [
  {
      name: 'Example',
      path: '/',
      component: Example
  }
];

const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');

I have created an array of routes and passed them to the router object.

So, your whole app.js file will look like this.

// app.js

import Vue from 'vue';

import VueRouter from 'vue-router';
Vue.use(VueRouter);

import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);

import App from './App.vue';
import Example from './components/Example.vue';

const routes = [
  {
      name: 'Example',
      path: '/',
      component: Example
  }
];

const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');

Type the following command in your terminal if everything is set up correctly.

php artisan serve

It will start the server on port 8000. So in Chrome, switch to this URL: http://localhost:8000

Example component

Step 4: Create a Backend For Our Application.

The next step would be to move VueJS to Laravel and create a backend for our project. We can use Web routes or API routes, and for this project, let us stick with web routes, so we need to put all of our routes in the routes  >>  web.php file.

First, we are going to perform CRUD operations on items. So first, let us define the schema for it. Then we will create controllers and routes.

Go to your command line and type the following command. First, ensure you are at the root of our project folder.

php artisan make:model Item -m

It will create two files.

  1. Model file.
  2. Migration file.

Go to the migration file in the database  >>  migrations  >>  create_items_table and copy the following code.

<?php

// create_items_table

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

class CreateItemsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->integer('price');
            $table->timestamps();
        });
    }

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

Go to the terminal and type the following command.

php artisan migrate

It creates the items table in the database. Also, one model file is created in the app folder.

It is time to create one resource controller called ItemController by typing the following command.

php artisan make:controller ItemController --resource

This ItemController contains all its methods of CRUD operations. But first, we need to put the code in it.

So, I am now putting the whole file with all the operations.

<?php

// ItemController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Item;

class ItemController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $items = Item::all();
        return response()->json($items);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $item = new Item([
          'name' => $request->get('name'),
          'price' => $request->get('price')
        ]);
        $item->save();
        return response()->json('Successfully added');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $item = Item::find($id);
        return response()->json($item);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $item = Item::find($id);
        $item->name = $request->get('name');
        $item->price = $request->get('price');
        $item->save();

        return response()->json('Successfully Updated');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
      $item = Item::find($id);
      $item->delete();

      return response()->json('Successfully Deleted');
    }
}

We also need to create a protected $fillable field in the Item.php file; otherwise, a ‘mass assignment exception‘ will be thrown.

<?php

// Item.php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    protected $fillable = ['name', 'price'];
}

The last step would be registering the routes in the routes >> web.php file.

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
 return view('welcome');
});
Route::resource('items', 'ItemController');

Step 5: Make three components and register with the App component.

All of our Backend is almost done. Now, if we switch to the front end in Vue.js, we need to create three components and include them in an app.js file to register the routes, and it is good to go.

Create the following components inside resources  >>  assets  >>  js  >>  components.

  1. CreateItem.vue
  2. EditItem.vue
  3. DisplayItem.vue
// CreateItem.vue

<template>
  <div>
    <h1>Create An Item</h1>
    <form v-on:submit.prevent="addItem">
      <div class="row">
        <div class="col-md-6">
          <div class="form-group">
            <label>Item Name:</label>
            <input type="text" class="form-control" v-model="item.name">
          </div>
        </div>
        </div>
        <div class="row">
          <div class="col-md-6">
            <div class="form-group">
              <label>Item Price:</label>
              <input type="text" class="form-control col-md-6" v-model="item.price" />
            </div>
          </div>
        </div><br />
        <div class="form-group">
          <button class="btn btn-primary">Add Item</button>
        </div>
    </form>
  </div>
</template>
<script>
  export default {
    data(){
        return{
          item:{}
        }
    },
    methods: {
      addItem(){
        let uri = 'http://localhost:8000/items';
        this.axios.post(uri, this.item).then((response) => {
          this.$router.push({name: 'DisplayItem'})
        })
    }
  }
}
</script>

Here, I have defined the template, a basic Item creation form. Then, in Javascript, I have to define the item object and post method to post the data to the Laravel backend server.

This file must be included in the app.js file to register the routes to see the form.

Okay, now create another component called DisplayItem.vue in the components folder.

// EditItem.vue

<template>
    <div>
        <h1>Items</h1>

        <div class="row">
          <div class="col-md-10"></div>
          <div class="col-md-2">
            <router-link :to="{ name: 'CreateItem' }" class="btn btn-primary">Create Item</router-link>
          </div>
        </div><br />

        <table class="table table-hover">
            <thead>
            <tr>
                <td>ID</td>
                <td>Item Name</td>
                <td>Item Price</td>
                <td>Actions</td>
            </tr>
            </thead>

            <tbody>
                <tr v-for="item in items">
                    <td>{{ item.id }}</td>
                    <td>{{ item.name }}</td>
                    <td>{{ item.price }}</td>
                    <td><router-link :to="{name: 'EditItem', params: { id: item.id }}" class="btn btn-primary">Edit</router-link></td>
                    <td><button class="btn btn-danger" v-on:click="deleteItem(item.id)">Delete</button></td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script>

    export default {
        data(){
            return{
                items: []
            }
        },

        created: function()
        {
            this.fetchItems();
        },

        methods: {
            fetchItems()
            {
              let uri = 'http://localhost:8000/items';
              this.axios.get(uri).then((response) => {
                  this.items = response.data;
              });
            },
            deleteItem(id)
            {
              let uri = `http://localhost:8000/items/${id}`;
              this.items.splice(id, 1);
              this.axios.delete(uri);
            }
        }
    }
</script>

Here, I have written the component that displays the items in a tabular form, and also, I have defined two other buttons one is for EditItem.vue, and the other is the Delete function.

We also need to create the third and final component called EditItem.vue component.

// EditItem.vue

<template>
    <div>
        <h1>Update Item</h1>
        <div class="row">
          <div class="col-md-10"></div>
          <div class="col-md-2"><router-link :to="{ name: 'DisplayItem' }" class="btn btn-success">Return to Items</router-link></div>
        </div>

        <form v-on:submit.prevent="updateItem">
            <div class="form-group">
                <label>Item Name</label>
                <input type="text" class="form-control" v-model="item.name">
            </div>

            <div class="form-group">
                <label name="product_price">Item Price</label>
                <input type="text" class="form-control" v-model="item.price">
            </div>

            <div class="form-group">
                <button class="btn btn-primary">Update</button>
            </div>
        </form>
    </div>
</template>

<script>

    export default{
        data(){
            return{
                item:{}
            }
        },

        created: function(){
            this.getItem();
        },

        methods: {
            getItem()
            {
              let uri = `http://localhost:8000/items/${this.$route.params.id}/edit`;
                this.axios.get(uri).then((response) => {
                    this.item = response.data;
                });
            },

            updateItem()
            {
              let uri = 'http://localhost:8000/items/'+this.$route.params.id;
                this.axios.patch(uri, this.item).then((response) => {
                  this.$router.push({name: 'DisplayItem'});
                });
            }
        }
    }
</script>

Here, I have defined the Update function with its POST request.

The last step is to include all these components in the app.js file.

We can now remove the Example.vue component, as we do not need it anymore.

// app.js

import Vue from 'vue';

import VueRouter from 'vue-router';
Vue.use(VueRouter);

import VueAxios from 'vue-axios';
import axios from 'axios';
Vue.use(VueAxios, axios);

import App from './App.vue';
import CreateItem from './components/CreateItem.vue';
import DisplayItem from './components/DisplayItem.vue';
import EditItem from './components/EditItem.vue';

const routes = [
  {
    name: 'CreateItem',
    path: '/items/create',
    component: CreateItem
  },
  {
        name: 'DisplayItem',
        path: '/',
        component: DisplayItem
  },
  {
      name: 'EditItem',
      path: '/edit/:id',
      component: EditItem
   }
];

const router = new VueRouter({ mode: 'history', routes: routes});
new Vue(Vue.util.extend({ router }, App)).$mount('#app');

Finally, go to http://localhost:8000.

List Items

If you have any data, the home screen will look like this if you click the Create Item button.

Create Interface

If you click on the Edit button, this will be your page.

Update interface

Download the Project On Github

That’s it.

43 thoughts on “How to Create Laravel with Vue CRUD Application”

  1. Great tutorial dude, I learn a lot from you.

    One suggestion though, for the delete method, you should do loop with index.
    If you splice the id, it can be different value between the item index position and the id value, because the id is auto incremented. The splice method doesnt find the start parameter if the id is larger so the items data isn’t updated.

    the directive:

    the button:
    Delete

    the function:
    let uri = `http://localhost/items/${id}`;
    this.items.splice(index,1);
    this.axios.delete(uri);

    Reply
  2. I have a problem now. As you said, web.php contains ‘resource’ route for ‘items’ and Vue is using ‘items’ too.

    So when you are clicking the links and travel through javascript, everything is ok, but when you press F5 on your keyboard or try to access localhost:8000/edit/1, the web.php file comes in and says there is no route for ‘edit’!

    Reply
      • Hi Krunal,

        Thanks for this tutorial, it’s really helpful to understand the concept.
        However, I got an empty page though the items table contains 4 items.
        Do you know what it could be behind the empty page?

        Reply
  3. A very great and super cool tutorial.
    Thanks for putting this together.

    I think you make the call to fetchItems ( i.e this.fetchItems(); )when any item is deleted, with this, the view is refreshed without having to refresh the page.

    deleteItem(id)
    {
    let uri = `http://127.0.0.1:9900/items/${id}`;
    this.items.splice(id, 1);
    this.axios.delete(uri);
    this.fetchItems();
    }

    Reply
  4. I think you we can also make the call to fetchItems ( i.e this.fetchItems(); ) when any item is deleted, with that the view data is refreshed without having to refresh the whole page.

    deleteItem(id)
    {
    let uri = `http://127.0.0.1:9900/items/${id}`;
    this.items.splice(id, 1);
    this.axios.delete(uri);
    this.fetchItems();
    }

    In all, a very great tutorial.

    Reply
  5. I think we can also make the call to fetchItems ( i.e this.fetchItems(); ) when any item is deleted, with that the view data is refreshed without having to refresh the whole page.

    deleteItem(id)
    {
    let uri = `http://127.0.0.1:9900/items/${id}`;
    this.items.splice(id, 1);
    this.axios.delete(uri);
    this.fetchItems();
    }

    In all, a very great tutorial.

    Reply
    • This can be accomplished by adding/modifying the elements with an Index inside DisplayItem component:
      1. Adding an Index to v-for and v-on:click

      Delete
      2. And in the deleteItem method
      deleteItem(index, id)
      {
      let uri = `/items/${id}`;
      this.items.splice(index, 1);
      this.axios.delete(uri);
      }

      Reply
  6. Hello There,

    Thanks for great tutorial.

    I have seen that and working fine in my local system @http://localhost:8000

    But while i am running this project without “php artisan serve”, And with url: “http://192.168.2.212/vuedemo/laravue2/public/”, it is not displaying records.

    Above URL is of my local system.

    Please suggest me how to run project without “php artisan serve”. I have placed code in apache htdocs directory.

    Thanks in advance.

    Reply
    • Hi,

      I got an empty page, no table, no create,no edit, no delete though the table has 4 items inserted in MySQL database, no component displayed at all.
      Anyone could help on the empty page?

      Reply
  7. Hi, when I delete the items, the table is not refreshing, should I add
    this.axios.patch(uri, this.item).then((response) => {
    this.$router.push({name: ‘DisplayItem’});
    });

    ?

    Reply
  8. In step 2, could you specify what config file you are editing? I don’t see any mention of the filename and I’m not sure where this file should be.

    Reply
  9. wow nice tutorial.
    but why this not work in laravel 5.6?? or i am missing some step??
    the page shown like in example. but the back-end somehow does not catch the data..

    Reply
  10. Thank you for this tutorial ,, i have one problem is when my laravel&vuejs app on shared hosting the vue components doesn’t change after editing. I don’t encounter this problem on local server because i run “npm run watch” to compile assets. but on shared hosting i didn’t find a way to do that.

    Reply
  11. I recently upgraded to 5.6 from 5.2 going step by step through 5.3-5.4-5.5.
    Do I need to manually copy the app.js to resources/asses/js folder?
    I don’t see it there.

    Reply
  12. I got an empty page, no table, no create,no edit, no delete though the table has 4 items inserted in MySQL database, no component displayed at all.
    Anyone could help on the empty page?

    Reply
  13. @Krunal, do you know how to create baseURL in vue? I want to set it so that in future i can change it at only one place

    Reply
  14. I’m getting path issues with the REPO version. Components is on the same level as the js/app.js that seems to expect it INSIDE the js folder. Is there something I’m missing with the path setup?

    Reply

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.