Laravel 5.5 CRUD operation with Vuejs 2.0 step by step explanation

Abhigyan Singh 12th Jul 2020

On my previous article I had shown you how to do CRUD operation using Laravel. In this article I am going to take it to the next level. I am going to show you to do CRUD operation using Vuejs with Laravel.

Scope of this project:

Using Vuejs with Laravel APIs is not an easy job for beginners.

In this project we will create one simple Laravel project and I will show you how to add frontend dependencies using nodejs/npm for vuejs and again create Todo application using Vuejs 2 and Laravel 5.5 APIs.

Project prerequisites:

  • Windows 7
  • Wampserver 3.0.6
  • Composer
  • Laravel 5.5
  • Vuejs 2

Tutorial’s outlines:

  1. Database design
  2. Use built-in authentication
  3. Create migration, model, resource controller, resource routes scaffolding
  4. Define schema inside migration file and run it
  5. Use NPM to install frontend dependencies
  6. Define Todo routes
  7. List Todos
  8. Create Todo
  9. Update Todo
  10. Delete Todo

Database Design

We are going to same database design which we have used in previous tutorial. We will allow users to register their self and create their own to-do list. For our to-do list project we will use this database design:

Use built-in Authentication

One of the essential features almost every project needed is authentication. Laravel provides built-in authentication, which is easy to implement. So we are going to use it in this project. Laravel comes with a command-line interface which helps you to auto-generate some of the essential things.

 

Once you execute this artisan command it will generate all the necessary files required for authentication. Now we have authentication functionality available with remember me and forgot password.

Before proceed further you have to fill database credentials in your .env file.

 

Before try to run your migration you have to follow few steps to avoid this error regarding specified key is too long.

To fix this error you have to go todo/app/Providers/AppServiceProvider.php and add this 2 line:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
?>

Now you can run your migration using this artisan command:

php artisan migrate

This artisan command will run all the migrations which are generated in database/migrations directory.

Create migration, model, resource controller, resource routes

Now it’s time to create migration, model and resource controller for our todo table. We have single artisan command to auto generate all this stuff which save your lot of time.

Define schema inside migration file and run it

Now we have generated migration, model and controller. It’s time to define schema inside our migration file.


<?php

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

class CreateTodosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->foreign('user_id')->references('id')->on('users');
			$table->text('description')->nullable();
			$table->boolean('is_completed');
            $table->timestamps();
        });
    }

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

Now we will run artisan command to run this new migration file.

Use NPM to install frontend dependencies

To install frontend dependencies for vuejs we have to install Nodejs which comes with it’s dependency manager called NPM. Installing Nodejs is a same process as you are installing any other windows application. Once you install Nodejs then the next task is to access your project root from command line and run command npm install.

Define Todo routes

Open routes/web.php and add following line in it:

Route::resource('todos', 'TodoController');

This will take care of all the routes which is defined for todos.

List Todos

Laravel provides basic scaffolding for Vuejs. Now we can easily start using it for our todo project. We will use Laravel Mix for asset compilation process. You need to run this command in separate terminal to compile our assets after make changes in it:

npm run watch

Listing Todos using Vuejs is a whole new way than you doing it in a traditional way. Now you don’t need to loop through todos collection using blade. Now you need to access APIs to fetch all the todos in json format and decode it to use it in javascript.

We will create data and methods object along with created method. Initially we are going to store all the data fetch from API inside todos array and loop it through using v-for loop.

We have defined fetchTodoList method which will fetch all the todos data from API and created method will be called when Vue object is initialized.

resources/assets/js/app.js

<?php
require('./bootstrap');

window.Vue = require('vue');

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

const app = new Vue({
    el: '#app',
	
    data: {
        todos: [],
    },
	
    created() {
        this.fetchTodoList();
    },

    methods: {
        fetchTodoList() {
            axios.get('/todos').then((res) => {
                this. todos= res.data;
            });
        },
    }
});


?>

Blade and Vuejs both using double curly braces to render their variable, so to avoid conflict we will append @ sign before that so it will be ignored by blade engine.

resources/views/home.blade.php

<?php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Todos List</div>
                <div class="panel-body">
			<table class="table">
				<tr>
					<th>Description</th>
					<th>Is completed?</th>
				</tr>
				<tr v-for="todo in todos" class="list-group-item">
					<td>@{{todo.description}}</td>
					<td>@{{todo.is_completed}}</td>
				</tr>
			</table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

?>

app/Http/Controller/TodoController.php

<?php

namespace App\Http\Controllers;

use App\Todo;
use Illuminate\Http\Request;

class TodoController extends Controller
{
    public function index()
    {
        return Todo::where('user_id',auth()->user()->id)->get();
    }
    …
}

?>

Create Todo

We will follow similar approach that we have followed to list todos. We will create new javascript object named newTodo, which as similar properties that we have in our eloquent model.

We will create one more method inside methods named addTodo, which will send newTodo object to a post API. We have reset newTodo object’s properties and called fetchTodoList to re-render Todo List.

Make following changes in these files:

resources/assets/js/app.js

<?php
require('./bootstrap');

window.Vue = require('vue');

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

const app = new Vue({
    el: '#app',
	
    data: {
        todos: [],
        newTodo: {
            id: '',
            description: '',
		is_completed: ''
        },
    },
	
    …


    methods: {
        …
        addTodo() {
            axios.post('/todos',this.newTodo)
            .then((res) => {
                this.newTodo.description = '';
                this.newTodo.is_completed = '';
                this.fetchTodoList();
            })
            .catch((err) => console.error(err));
        },
    }
});


?>

We have created one form to grab input from user and use vuejs directives to collect data from form and send it to server through API.

resources/views/home.blade.php

<?php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Todos List</div>

                <div class="panel-body">
			<table class="table table-bordered">
			<tr>
				<th>Description</th>
				<th>Is completed?</th>
			</tr>
			<tr v-for="todo in todos">
				<td>@{{todo.description}}</td>
				<td>@{{todo.is_completed}}</td>
			</tr>
			</table>
			<div class="form-group">
				<form method="POST" action="#" @submit.prevent="addTodo()">
				<div class="col-md-8">
				<input type="text" class="form-control" placeholder="Enter Description" v-model="newTodo.description" name="description" />
			<input type="checkbox" v-model="newTodo.is_completed" name="is_completed" id="is_completed" value="1" />
				<label for="is_compeleted">Is completed?</label>
				</div>
				<div class="col-md-2">
	<button class="btn btn-primary" type="submit">Add Todo</button>
				</div>
				</form>
			</div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

?>

app/Http/Controller/TodoController.php

<?php

namespace App\Http\Controllers;

use App\Todo;
use Illuminate\Http\Request;

class TodoController extends Controller
{

    public function store(Request $request)
    {
	$todo = new Todo();
	$todo->user_id = auth()->user()->id;
	$todo->description = $request->description;
	if($request->has('is_completed')){
		$todo->is_completed = 1;
	}else{
		$todo->is_completed = 0;
	}
    	if($todo->save()){
		return ['success'=>true]; 
	}  
    	return ['success'=>false]; 
    }

}

?>

Update Todo

To update todos we have added one property inside data object named createdMode, which will decide whether to show create form or edit form in a view.

We have defined one more method inside methods object named updateTodo. This method will collect updated data and pass it on to the update API. We have used same newTodo object to store updated data.

Make following changes in these files:

resources/assets/js/app.js

<?php
require('./bootstrap');

window.Vue = require('vue');

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

const app = new Vue({
    el: '#app',
	
    data: {
        todos: [],
        newTodo: {
            id: '',
            description: '',
		is_completed: ''
        },
        createMode: true,
    },
	
    methods: {
        editTodo(todo)  {
            this.newTodo.id = todo.id;
            this.newTodo.description = todo.description;
            this.newTodo.is_completed = todo.is_completed;
            this.createMode = false;
        },

        updateTodo(){
            axios.put('/todos/'+this.newTodo.id, this.newTodo)
            .then((res) => {
                this.fetchTodoList();
                this.newTodo.id = '';
                this.newTodo.description = '';
		     this.newTodo.is_completed = '';
                this.createMode = true;
            });
        },
    }
});

?>

resources/views/home.blade.php

<?php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Todos List</div>

                <div class="panel-body">
					<table class="table table-bordered">
						<tr>
							<th>Description</th>
							<th>Is completed?</th>
							<th>Actions</th>
						</tr>
						<tr v-for="todo in todos">
							<td>@{{todo.description}}</td>
							<td>@{{todo.is_completed}}</td>
							<td>
                                <button class="btn btn-primary" @click="editTask(task)">Edit</button>
							</td>
						</tr>
					</table>
			<div class="form-group" v-if="createMode">
				<form method="POST" action="#" @submit.prevent="addTodo()">
				<div class="col-md-8">
				<input type="text" class="form-control" placeholder="Enter Description" v-model="newTodo.description" name="description" />
				<input type="checkbox" v-model="newTodo.is_completed" name="is_completed" id="is_completed" value="1" />
				<label for="is_compeleted">Is completed?</label>
				</div>
				<div class="col-md-2">
			<button class="btn btn-primary" type="submit">Add Todo</button>
				</div>
				</form>
			</div>
			<div class="form-group" v-else="createMode">
			<form method="POST" action="#" @submit.prevent="updateTodo()">
					<div class="col-md-8">
					<input type="text" class="form-control" v-model="newTodo.description" name="description" />
					<input type="checkbox" v-model="newTodo.is_completed" name="is_completed" id="is_completed" value="1" />
					<label for="is_compeleted">Is completed?</label>
					</div>
					<div class="col-md-2">
			<button class="btn btn-primary" type="submit">Update Todo</button>
					</div>
			</form>
			</div>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

?>

app/Http/Controller/TodoController.php

<?php

namespace App\Http\Controllers;

use App\Todo;
use Illuminate\Http\Request;

class TodoController extends Controller
{
    
    public function update(Request $request, $id)
    {
        $todo = Todo::find($id);
	  $todo->user_id = auth()->user()->id;
	  $todo->description = $request->description;
	  if($request->has('is_completed')){
		$todo->is_completed = 1;
	  }else{
		$todo->is_completed = 0;
	  }
    	  if($todo->save()){
		return ['success'=>true]; 
	  }  
    	  return ['success'=>false]; 
    }

}

?>

Delete Todo

To delete todo we have just added removeTodo method inside methods object. This will call delete API with specific todo id to delete it from the database.

Make following changes in these files:

resources/assets/js/app.js

<?php
require('./bootstrap');

window.Vue = require('vue');

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

const app = new Vue({
    el: '#app',
	
    data: {
        todos: [],
        newTodo: {
            id: '',
            description: '',
		is_completed: ''
        },
        createMode: true,
    },
	
    created() {
        this.fetchTodoList();
    },

    methods: {
        fetchTodoList() {
            axios.get('/todos').then((res) => {
                this.todos = res.data;
            });
        },
        removeTodo(id) {
            axios.delete('/todos/' + id)
            .then((res) => {
                this.fetchTodoList()
            })
            .catch((err) => console.error(err));
        },
    }
});



?>

resources/views/home.blade.php

<?php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Todos List</div>

                <div class="panel-body">
					<table class="table table-bordered">
						<tr>
							<th>Description</th>
							<th>Is completed?</th>
							<th>Actions</th>
						</tr>
						<tr v-for="todo in todos">
							<td>@{{todo.description}}</td>
							<td>@{{todo.is_completed}}</td>
							<td>
                                <button class="btn btn-primary" @click="editTodo(todo)">Edit</button>
								<button class="btn btn-danger" @click="removeTodo(todo.id)">Delete</button>
							</td>
						</tr>
					</table>
…
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
 

?>

app/Http/Controller/TodoController.php

<?php

namespace App\Http\Controllers;

use App\Todo;
use Illuminate\Http\Request;

class TodoController extends Controller
{    
    public function destroy($id)
    {
        $todo = Todo::find($id);
        $todo->delete();
        return ['success'=>true];
    }
}

?>

That’s it! I have showed you simplest way to perform CRUD using Vuejs without using vue-router.

Authored By Abhigyan Singh

He is a continuous blogger and has blogged on different topic. He loves to surf Internet and always trying to get new Idea about new Technology and Innovations and sharing these great information to all the technology lovers.

ALSO ON DISCUSS DESK