Laravel 5.5 CRUD operation with Vuejs 2.0 step by step explanation

Manas Singh 24th Sep 2020

In 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 of CRUD operation. 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 a 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 the 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 the same database design which we have used in the previous tutorial. We will allow users to register themself 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 that 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 to remember me and forgot password.

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

 

Before trying to run your migration you have to follow few steps to avoid this error regarding the 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 the database/migrations directory.

Create migration, model, resource controller, resource routes

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

Define schema inside the 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 the 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 its dependency manager called NPM. Installing Nodejs is the 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 the command line and run command npm install.

Define Todo routes

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

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

This will take care of all the routes which are 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 the asset compilation process. You need to run this command in a separate terminal to compile our assets after making 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 the todos collection using a 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 the created method. Initially, we are going to store all the data fetch from API inside the todos array and loop it through using the v-for loop.

We have defined the fetchTodoList method which will fetch all the todos data from API and the created method will be called when the 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 the 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 a similar approach that we have followed to list todos. We will create a new javascript object named newTodo, which as similar properties that we have in our eloquent model.

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

Make the 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 the user and use vuejs directives to collect data from the form and send it to the 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 the 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 the methods object named updated todo operation. This method will collect updated data and pass it on to the update API. We have used the same new todo object to store updated data.

Make the 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 the removed method inside the methods object. This will call delete API with a specific todo id to delete it from the database.

Make the 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 shown you the simplest way to perform CRUD operation using Vuejs without using Vue-router.

Authored By Manas 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 DiscussDesk