Laravel and Vue JS CRUD with Pagination ?

Today now in this post i will show you Laravel and Vue JS CRUD with Pagination ? In Todays, we know that Most popular JS Framework are Angular JS and Vue JS. Angular JS and Vue JS both are very user friendly JS Framework and also most popular. It is provides us to manage whole project or application without any refresh page and also powerful jquery validation.

Now in this post i am going to lean you how to create CRUD(Create, Read, Update and Delete) application also with pagination by using Laravel 8.

Work Out Line

Here in this example i will add “Item Management” with you can do that several option as like as bellow:

  • Item Listing
  • Item Create
  • Item Edit
  • Item Delete

I will implement the crud application from the scratch. So no worry if you can know through the 0bellow simple step.

Step 1: Laravel Installation

Now in first step, if you don’t have installed Laravel in your system then you need to run the bellow command and you will get a fresh Laravel project.

composer create-project --prefer-dist laravel/laravel blog
Step 2: Create items table and model

So in this step we need to create a model with migration for items table by using Laravel php artisan command, so first need to fire bellow command:

php artisan make:model Item

After this command we will find one new file in the following path database/migrations and we need to put the bellow code in our migration file for create the items table.

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


class CreateItemsTable extends Migration
{

    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('description');
            $table->timestamps();
        });
    }


    public function down()
    {
        Schema::drop("items");
    }
}

So after the create “items” table we can find Item file in this path app/Models/Item.php and put the bellow content in item.php file:

app/Models/Item.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Item extends Model
{
    public $fillable = ['title','description'];
}
Step 3: Add Route and Controller

Now we need to add new route for items CRUD and also pagination. In this example i will added the resource route and one for the manage-vue for application, if we need to add resource route then it will add the index, create, edit and delete route automatically. So just add the bellow line in your web file.

routes/web.php
Route::get('manage-vue', 'VueItemController@manageVue');
Route::resource('vueitems','VueItemController');

Ok, now we should need to create new controller as name VueItemController in this path app/Http/Controllers/VueItemController.php. This controller will manage all the route method:

app/Http/Controllers/VueItemController.php
namespace App\Http\Controllers;


use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Models\Item;


class VueItemController extends Controller
{


    public function manageVue()
    {
        return view('manage-vue');
    }


    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $items = Item::latest()->paginate(5);


        $response = [
            'pagination' => [
                'total' => $items->total(),
                'per_page' => $items->perPage(),
                'current_page' => $items->currentPage(),
                'last_page' => $items->lastPage(),
                'from' => $items->firstItem(),
                'to' => $items->lastItem()
            ],
            'data' => $items
        ];


        return response()->json($response);
    }


    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request, [
            'title' => 'required',
            'description' => 'required',
        ]);


        $create = Item::create($request->all());


        return response()->json($create);
    }


    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request, [
            'title' => 'required',
            'description' => 'required',
        ]);


        $edit = Item::find($id)->update($request->all());


        return response()->json($edit);
    }


    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        Item::find($id)->delete();
        return response()->json(['done']);
    }
}
Step 4: Create Blade File

Now in this step we need to create only one blade file on that will manage create, update and delete operation of items module also with vue js.

Now in this file i will added jquery, bootstrap js and css, vue.js, vue-resource.min.js, toastr js and also css for notification in this blade file.

So, let’s need to create manage-vue.blade.php file on the following way:

resources/views/manage-vue.blade.php
<!DOCTYPE html>
<html>
<head>
	<title>Laravel Vue JS Item CRUD- CodingsPoint </title>
	<meta id="token" name="token" value="{{ csrf_token() }}">
	<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css">
</head>
<body>


	<div class="container" id="manage-vue">


		<div class="row">
		    <div class="col-lg-12 margin-tb">
		        <div class="pull-left">
		            <h2>Laravel Vue JS Item CRUD</h2>
		        </div>
		        <div class="pull-right">
				<button type="button" class="btn btn-success" data-toggle="modal" data-target="#create-item">
				  Create Item
				</button>
		        </div>
		    </div>
		</div>


		<!-- Item Listing -->
		<table class="table table-bordered">
			<tr>
				<th>Title</th>
				<th>Description</th>
				<th width="200px">Action</th>
			</tr>
			<tr v-for="item in items">
				<td>@{{ item.title }}</td>
				<td>@{{ item.description }}</td>
				<td>	
			      <button class="btn btn-primary" @click.prevent="editItem(item)">Edit</button>
			      <button class="btn btn-danger" @click.prevent="deleteItem(item)">Delete</button>
				</td>
			</tr>
		</table>


		<!-- Pagination -->
		<nav>
	        <ul class="pagination">
	            <li v-if="pagination.current_page > 1">
	                <a href="#" aria-label="Previous"
	                   @click.prevent="changePage(pagination.current_page - 1)">
	                    <span aria-hidden="true">«</span>
	                </a>
	            </li>
	            <li v-for="page in pagesNumber"
	                v-bind:class="[ page == isActived ? 'active' : '']">
	                <a href="#"
	                   @click.prevent="changePage(page)">@{{ page }}</a>
	            </li>
	            <li v-if="pagination.current_page < pagination.last_page">
	                <a href="#" aria-label="Next"
	                   @click.prevent="changePage(pagination.current_page + 1)">
	                    <span aria-hidden="true">»</span>
	                </a>
	            </li>
	        </ul>
	    </nav>


	    <!-- Create Item Modal -->
		<div class="modal fade" id="create-item" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
		  <div class="modal-dialog" role="document">
		    <div class="modal-content">
		      <div class="modal-header">
		        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
		        <h4 class="modal-title" id="myModalLabel">Create Item</h4>
		      </div>
		      <div class="modal-body">


		      		<form method="POST" enctype="multipart/form-data" v-on:submit.prevent="createItem">


		      			<div class="form-group">
						<label for="title">Title:</label>
						<input type="text" name="title" class="form-control" v-model="newItem.title" />
						<span v-if="formErrors['title']" class="error text-danger">@{{ formErrors['title'] }}</span>
					</div>


					<div class="form-group">
						<label for="title">Description:</label>
						<textarea name="description" class="form-control" v-model="newItem.description"></textarea>
						<span v-if="formErrors['description']" class="error text-danger">@{{ formErrors['description'] }}</span>
					</div>


					<div class="form-group">
						<button type="submit" class="btn btn-success">Submit</button>
					</div>


		      		</form>

		        
		      </div>
		    </div>
		  </div>
		</div>


		<!-- Edit Item Modal -->
		<div class="modal fade" id="edit-item" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
		  <div class="modal-dialog" role="document">
		    <div class="modal-content">
		      <div class="modal-header">
		        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
		        <h4 class="modal-title" id="myModalLabel">Edit Item</h4>
		      </div>
		      <div class="modal-body">


		      		<form method="POST" enctype="multipart/form-data" v-on:submit.prevent="updateItem(fillItem.id)">


		      			<div class="form-group">
						<label for="title">Title:</label>
						<input type="text" name="title" class="form-control" v-model="fillItem.title" />
						<span v-if="formErrorsUpdate['title']" class="error text-danger">@{{ formErrorsUpdate['title'] }}</span>
					</div>


					<div class="form-group">
						<label for="title">Description:</label>
						<textarea name="description" class="form-control" v-model="fillItem.description"></textarea>
						<span v-if="formErrorsUpdate['description']" class="error text-danger">@{{ formErrorsUpdate['description'] }}</span>
					</div>


					<div class="form-group">
						<button type="submit" class="btn btn-success">Submit</button>
					</div>


		      		</form>


		      </div>
		    </div>
		  </div>
		</div>


	</div>


	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.min.js"></script>


	<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script>
        <link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet">


	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script>
	<script type="text/javascript" src="https://cdn.jsdelivr.net/vue.resource/0.9.3/vue-resource.min.js"></script>


	<script type="text/javascript" src="/js/item.js"></script>


</body>
</html>
Step 5: Create JS File

So we are in last step we need to create one as name item.js file, at first we need to create a new folder as “js” in public directory and then need to create item.js file inside of this folder.

item.js file through we can manage the item pagination, create edit delete task and also with ajax method.

public/js/item.js
Vue.http.headers.common['X-CSRF-TOKEN'] = $("#token").attr("value");


new Vue({


  el: '#manage-vue',


  data: {
    items: [],
    pagination: {
        total: 0, 
        per_page: 2,
        from: 1, 
        to: 0,
        current_page: 1
      },
    offset: 4,
    formErrors:{},
    formErrorsUpdate:{},
    newItem : {'title':'','description':''},
    fillItem : {'title':'','description':'','id':''}
  },


  computed: {
        isActived: function () {
            return this.pagination.current_page;
        },
        pagesNumber: function () {
            if (!this.pagination.to) {
                return [];
            }
            var from = this.pagination.current_page - this.offset;
            if (from < 1) {
                from = 1;
            }
            var to = from + (this.offset * 2);
            if (to >= this.pagination.last_page) {
                to = this.pagination.last_page;
            }
            var pagesArray = [];
            while (from <= to) {
                pagesArray.push(from);
                from++;
            }
            return pagesArray;
        }
    },


  ready : function(){
  		this.getVueItems(this.pagination.current_page);
  },


  methods : {


        getVueItems: function(page){
          this.$http.get('/vueitems?page='+page).then((response) => {
            this.$set('items', response.data.data.data);
            this.$set('pagination', response.data.pagination);
          });
        },


        createItem: function(){
		  var input = this.newItem;
		  this.$http.post('/vueitems',input).then((response) => {
		    this.changePage(this.pagination.current_page);
			this.newItem = {'title':'','description':''};
			$("#create-item").modal('hide');
			toastr.success('Item Created Successfully.', 'Success Alert', {timeOut: 5000});
		  }, (response) => {
			this.formErrors = response.data;
	    });
	},


      deleteItem: function(item){
        this.$http.delete('/vueitems/'+item.id).then((response) => {
            this.changePage(this.pagination.current_page);
            toastr.success('Item Deleted Successfully.', 'Success Alert', {timeOut: 5000});
        });
      },


      editItem: function(item){
          this.fillItem.title = item.title;
          this.fillItem.id = item.id;
          this.fillItem.description = item.description;
          $("#edit-item").modal('show');
      },


      updateItem: function(id){
        var input = this.fillItem;
        this.$http.put('/vueitems/'+id,input).then((response) => {
            this.changePage(this.pagination.current_page);
            this.fillItem = {'title':'','description':'','id':''};
            $("#edit-item").modal('hide');
            toastr.success('Item Updated Successfully.', 'Success Alert', {timeOut: 5000});
          }, (response) => {
              this.formErrorsUpdate = response.data;
          });
      },


      changePage: function (page) {
          this.pagination.current_page = page;
          this.getVueItems(page);
      }


  }


});

Read Also :Laravel Join with Subquery in Query Builder Example

Thanks for read. I hope it help you. For more you can follow us on facebook.

close

About Shahriar Sagor

My name is Shahriar sagor. I'm a developer. I live in Bangladesh and I love to write tutorials and tips that will help to other Developer's. I am a big fan of PHP, Javascript, JQuery, Laravel, Codeigniter, VueJS, AngularJS and Bootstrap from the early stage.

View all posts by Shahriar Sagor →