Sunday, June 19, 2016

Complete laravel ajax CRUD, search, sort and pagination

Suppose that your project root folder is here C:\wamp\www\test_laravel.

Please download this file public.rar and extract to your public folder (C:\wamp\www\test_laravel\public)

Step 1: Create table products in MySQL database


or you can download sample data from here.

Step 2: Connect your Laravel project to MySQL database.Go to edit this file C:\wamp\www\test_laravel\.env and update your database information


Step 3: Create model file Product.php in C:\wamp\www\test_laravel\app

Product.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{

}

Step 4: Edit route file (C:\wamp\www\test_laravel\app\Http\routes.php) and add
Route::controller('product', 'ProductController');

Step 5: Create some view files index.blade.php, list.blade.php, create.blade.php, update.blade.php, _form.blade.php in C:\wamp\www\test_laravel\resources\views\product (please create product folder if not exist)

index.blade.php
<!DOCTYPE html>
<html lang="en">
<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 Tutorials</title>
    <!-- Styles -->
    <link href="{{ asset('bootstrap-3.3.6/css/bootstrap.min.css') }}" rel="stylesheet">
</head>
<body>
<style>
    .loading {
        background: lightgoldenrodyellow url('{{asset('images/processing.gif')}}') no-repeat center 65%;
        height: 80px;
        width: 100px;
        position: fixed;
        border-radius: 4px;
        left: 50%;
        top: 50%;
        margin: -40px 0 0 -50px;
        z-index: 2000;
        display: none;
    }
</style>
<div class="container-fluid">
    <div class="row"></div>
    <div class="row">
        <div class="col-md-3"></div>
        <div class="col-md-6">
            <div id="content"></div>
        </div>
        <div class="col-md-3"></div>
    </div>
    <div class="loading"></div>
</div>
<!-- JavaScripts -->
<script src="{{ asset('js/jquery-1.11.2.min.js') }}"></script>
<script src="{{ asset('bootstrap-3.3.6/js/bootstrap.min.js') }}"></script>
<script>
    function ajaxLoad(filename, content) {
        content = typeof content !== 'undefined' ? content : 'content';
        $('.loading').show();
        $.ajax({
            type: "GET",
            url: filename,
            contentType: false,
            success: function (data) {
                $("#" + content).html(data);
                $('.loading').hide();
            },
            error: function (xhr, status, error) {
                alert(xhr.responseText);
            }
        });
    }
    $(document).ready(function () {
        ajaxLoad('product/list');
    });
</script>
</body>
</html>

list.blade.php
<h1 class="page-header">Product List
    <div class="pull-right">
        <a href="javascript:ajaxLoad('product/create')" class="btn btn-primary pull-right"><i
                    class="glyphicon glyphicon-plus-sign"></i> New</a>
    </div>
</h1>
<div class="col-sm-7 form-group">
    <div class="input-group">
        <input class="form-control" id="search" value="{{ Session::get('product_search') }}"
               onkeydown="if (event.keyCode == 13) ajaxLoad('{{url('product/list')}}?ok=1&search='+this.value)"
               placeholder="Search..."
               type="text">

        <div class="input-group-btn">
            <button type="button" class="btn btn-default"
                    onclick="ajaxLoad('{{url('product/list')}}?ok=1&search='+$('#search').val())"><i
                        class="glyphicon glyphicon-search"></i>
            </button>
        </div>
    </div>
</div>
<table class="table table-bordered table-striped">
    <thead>
    <tr>
        <th width="50px" style="text-align: center">No</th>
        <th>
            <a href="javascript:ajaxLoad('product/list?field=name&sort={{Session::get("product_sort")=="asc"?"desc":"asc"}}')">
                Name
            </a>
            <i style="font-size: 12px"
               class="glyphicon  {{ Session::get('product_field')=='name'?(Session::get('product_sort')=='asc'?'glyphicon-sort-by-alphabet':'glyphicon-sort-by-alphabet-alt'):'' }}">
            </i>
        </th>
        <th>
            <a href="javascript:ajaxLoad('product/list?field=unitprice&sort={{Session::get("product_sort")=="asc"?"desc":"asc"}}')">
                Unitprice
            </a>
            <i style="font-size: 12px"
               class="glyphicon  {{ Session::get('product_field')=='unitprice'?(Session::get('product_sort')=='asc'?'glyphicon-sort-by-alphabet':'glyphicon-sort-by-alphabet-alt'):'' }}">
            </i>
        </th>
        <th width="140px"></th>
    </tr>
    </thead>
    <tbody>
    <?php $i = 1;?>
    @foreach($products as $key=>$product)
        <tr>
            <td align="center">{{$i++}}</td>
            <td>{{$product->name}}</td>
            <td align="right">$ {{$product->unitprice}}</td>
            <td style="text-align: center">
                <a class="btn btn-primary btn-xs" title="Edit"
                   href="javascript:ajaxLoad('product/update/{{$product->id}}')">
                    <i class="glyphicon glyphicon-edit"></i> Edit</a>
                <a class="btn btn-danger btn-xs" title="Delete"
                   href="javascript:if(confirm('Are you sure want to delete?')) ajaxLoad('product/delete/{{$product->id}}')">
                    <i class="glyphicon glyphicon-trash"></i> Delete
                </a>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>
<div class="pull-right">{!! str_replace('/?','?',$products->render()) !!}</div>
<div class="row">
    <i class="col-sm-12">
        Total: {{$products->total()}} records
    </i>
</div>
<script>
    $('.pagination a').on('click', function (event) {
        event.preventDefault();
        ajaxLoad($(this).attr('href'));
    });
</script>

create.blade.php
<h2 class="page-header">New Product</h2>
{!! Form::open(["id"=>"frm","class"=>"form-horizontal"]) !!}
@include("product._form")
{!! Form::close() !!}


update.blade.php
<h2 class="page-header">Edit Product</h2>
{!! Form::model($product,["id"=>"frm","class"=>"form-horizontal"]) !!}
@include("product._form")
{!! Form::close() !!}


_form.blade.php
<div class="form-group required" id="form-name-error">
    {!! Form::label("name","Name",["class"=>"control-label col-md-3"]) !!}
    <div class="col-md-6">
        {!! Form::text("name",null,["class"=>"form-control required","id"=>"focus"]) !!}
        <span id="name-error" class="help-block"></span>
    </div>
</div>
<div class="form-group required" id="form-unitprice-error">
    {!! Form::label("unitprice","Unitprice",["class"=>"control-label col-md-3"]) !!}
    <div class="col-md-6">
        {!! Form::text("unitprice",null,["class"=>"form-control required"]) !!}
        <span id="unitprice-error" class="help-block"></span>
    </div>
</div>
<div class="form-group">
    <div class="col-md-6 col-md-push-3">
        <a href="javascript:ajaxLoad('product/list')" class="btn btn-danger"><i
                    class="glyphicon glyphicon-backward"></i>
            Back</a>
        {!! Form::button("<i class='glyphicon glyphicon-floppy-disk'></i> Save",["type" => "submit","class"=>"btn
    btn-primary"])!!}
    </div>
</div>
<script>
    $("#frm").submit(function (event) {
        event.preventDefault();
        $('.loading').show();
        var form = $(this);
        var data = new FormData($(this)[0]);
        var url = form.attr("action");
        $.ajax({
            type: "POST",
            url: url,
            data: data,
            async: false,
            cache: false,
            contentType: false,
            processData: false,
            success: function (data) {
                if (data.fail) {
                    $('#frm input.required, #frm textarea.required').each(function () {
                        index = $(this).attr('name');
                        if (index in data.errors) {
                            $("#form-" + index + "-error").addClass("has-error");
                            $("#" + index + "-error").html(data.errors[index]);
                        }
                        else {
                            $("#form-" + index + "-error").removeClass("has-error");
                            $("#" + index + "-error").empty();
                        }
                    });
                    $('#focus').focus().select();
                } else {
                    $(".has-error").removeClass("has-error");
                    $(".help-block").empty();
                    $('.loading').hide();
                    ajaxLoad(data.url, data.content);
                }
            },
            error: function (xhr, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });
        return false;
    });
</script>

Step 6: Create controller file ProductController.php in here C:\wamp\www\test_laravel\app\Http\Controllers 
<?php
namespace App\Http\Controllers;

use App\Product;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Validator;

class ProductController extends Controller
{
    public function getIndex()
    {
        return view('product.index');
    }

    public function getList()
    {
        Session::put('product_search', Input::has('ok') ? Input::get('search') : (Session::has('product_search') ? Session::get('product_search') : ''));
        Session::put('product_field', Input::has('field') ? Input::get('field') : (Session::has('product_field') ? Session::get('product_field') : 'name'));
        Session::put('product_sort', Input::has('sort') ? Input::get('sort') : (Session::has('product_sort') ? Session::get('product_sort') : 'asc'));
        $products = Product::where('name', 'like', '%' . Session::get('product_search') . '%')
            ->orderBy(Session::get('product_field'), Session::get('product_sort'))->paginate(8);
        return view('product.list', ['products' => $products]);
    }

    public function getUpdate($id)
    {
        return view('product.update', ['product' => Product::find($id)]);
    }

    public function postUpdate($id)
    {
        $product = Product::find($id);
        $rules = ["unitprice" => "required|numeric"];
        if ($product->name != Input::get('name'))
            $rules += ['name' => 'required|unique:products'];
        $validator = Validator::make(Input::all(), $rules);
        if ($validator->fails()) {
            return array(
                'fail' => true,
                'errors' => $validator->getMessageBag()->toArray()
            );
        }
        $product->name = Input::get('name');
        $product->unitprice = Input::get('unitprice');
        $product->save();
        return ['url' => 'product/list'];
    }

    public function getCreate()
    {
        return view('product.create');
    }

    public function postCreate()
    {
        $validator = Validator::make(Input::all(), [
            "name" => "required|unique:products",
            "unitprice" => "required|numeric"
        ]);
        if ($validator->fails()) {
            return array(
                'fail' => true,
                'errors' => $validator->getMessageBag()->toArray()
            );
        }
        $product = new Product();
        $product->name = Input::get('name');
        $product->unitprice = Input::get('unitprice');
        $product->save();
        return ['url' => 'product/list'];
    }

    public function getDelete($id)
    {
        Product::destroy($id);
        return Redirect('product/list');
    }

}

How to test? open your browser and type http://localhost/test_laravel/public/product. You will see this screen


20 comments:

About said...

Nice!

Evaria Ayu Nurjana said...
This comment has been removed by the author.
Evaria Ayu Nurjana said...

if ($validator->fails()) {
return array(
'fail' => true,
'errors' => $validator->getMessageBag()->toArray()
);
}

How do I catch the error and passing to alert?
It just passing to the web just like this, and alert didn't show this
{"fail":true,"errors":{"user_id":["The user id field is required."]}}

Senghok Eang said...

Hi Evaria,

It is ajax based CRUD, so you can check in javascript like this
$.ajax({
....
...
success: function (data) {
if (data.fail) {
alert(data.errors['user_id']);
},
....
...
});

Evaria Ayu Nurjana said...

Where should I add the code at list.blade.php or index.blade.php? I'm sorry, I am still learning ajax and still newbie

Evaria Ayu Nurjana said...

I've tried add the code
success: function (data) {
if (data.fail) {
$('#frm input.required, #frm select.required').each(function () {
index = $(this).attr('name');
$('.loading').hide();
if (index in data.errors) {
$("#form-" + index + "-error").addClass("has-error");
$("#" + index + "-error").html(data.errors[index]);
}
else {
$("#form-" + index + "-error").removeClass("has-error");
$("#" + index + "-error").empty();
}
});
$('#focus').focus().select();
alert(data.errors['user_id']);
...
still didn't work

Senghok Eang said...

It is validation in form so you should put this code in _form.php

Sergej Leginkov said...

Hi Senghok,

thanks for your tutorial Could you please also provide the retoute structure for Laravel 5.3 ?

As route:controller isn't working here anymore:
Route::controller('product', 'ProductController');

Help is much appreciated.

Dusty Darrell said...

This is an example of AJAX but a BAD example of a controller.

Rifki Chaplin said...

this is my routing, but when i save or update data, i got error "method not Allow".
can u help me ??

| GET|HEAD | product | | App\Http\Controllers\ProductsController@index | web |
| | GET|HEAD | product/create | | App\Http\Controllers\ProductsController@getCreate | web |
| | GET|HEAD | product/delete/{id} | | App\Http\Controllers\ProductsController@getDelete | web |
| | GET|HEAD | product/list | | App\Http\Controllers\ProductsController@getList | web |
| | POST | product/postcreate | | App\Http\Controllers\ProductsController@postCreate | web |
| | GET|HEAD | product/update/{id} | | App\Http\Controllers\ProductsController@getUpdate | web

Erick Nobleza said...

I'm getting this error "NotFoundHttpException in RouteCollection.php line 161:"

Fasiray said...

Thanks

Route::group(['middleware' => 'web'], function(){
Route::get('product','ProductController@getIndex');
Route::get('product/update/{id}','ProductController@getUpdate');
Route::post('product/update/','ProductController@postUpdate');
Route::get('product/create','ProductController@getCreate');
Route::post('product/create/','ProductController@postCreate');
Route::get('product/list','ProductController@getList');
Route::post('product/delete/{id}','ProductController@getDelete');
});

info care said...

I'm getting this error NotFoundHttpException in RouteCollection.php line 161:pls solve

Gautam said...

hi,

Is there any way i can contact you directly. This regarding article writing. Please let me know by replying to may email.

Nitesh Kumar said...

I really appreciate information shared above. It’s of great help. If someone want to learn Online (Virtual) instructor lead live training in AJAX, kindly contact us http://www.maxmunus.com/contact
MaxMunus Offer World Class Virtual Instructor led training on AJAX. We have industry expert trainer. We provide Training Material and Software Support. MaxMunus has successfully conducted 100000+ trainings in India, USA, UK, Australlia, Switzerland, Qatar, Saudi Arabia, Bangladesh, Bahrain and UAE etc.
For Demo Contact us.
Nitesh Kumar
MaxMunus
E-mail: nitesh@maxmunus.com
Skype id: nitesh_maxmunus
Ph:(+91) 8553912023
http://www.maxmunus.com/




Fabio Alexandre Pszepiura said...

Hello, First I want to thank for the example that is being very useful for some studies that I am doing.
I can't download the project files, so I find difficults in code $products->render() and $products->total(). Can you help me?

Anonymous said...

hello i thank you for this post. i used a part of it by modifying it but it works for me with laravel 5.3. i used only the search part.

Laravel Scots said...

Nice Article, keep Writing, Do you know you can also post your laravel related articles
on http://www.laravelinterviewquestions.com/submit-an-article too

Eric Kwakye said...

the download link is not working please help. or email tipsysmino@gmail.com

webwing said...

Nice post! thank you.
affordable web development company | best web design services