Laravel 8 Ajax Crud Image Upload Example Tutorial

Laravel 8 Ajax DataTable CRUD with image upload. In this post, i will show you how to build image upload ajax crud with datatable and bootstrap modal in laravel 8.

In this example article, i will build book ajax crud with image upload using datatable js and modal in laravel. And display image preview before upload.

And, you will learn how to add, edit, update and delete data with image upload data using datatables js, bootstrap modal and ajax in laravel 8. Also how to show image in datatable in laravel 8.

Laravel 8 Ajax CRUD with Image Upload using DataTables Tutorial

  • Step 1 – Installing Laravel 8 App
  • Step 2 – Configuring .evn file for Database
  • Step 3 – Installing Laravel Yajra DataTables
  • Step 4 – Create Model and Migration
  • Step 5 – Run Migration
  • Step 6 – Create Routes
  • Step 7 – Creating Datatables Controller
  • Step 8 – Create Action Button(delete and edit) Blade View
  • Step 9 – Show Image in Datatable
  • Step 10- Create DataTable Blade View
  • Step 11 – Start Development Server

Step 1 – Installing Laravel 8 App

In step 1, open your terminal and navigate to your local web server directory using the following command:

//for windows user
cd xampp/htdocs

//for ubuntu user
cd var/www/html

Then install laravel 8 latest application using the following command:

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

Step 2 – Configuring .evn file for Database

In step 2, open your downloaded laravel 8 app into any text editor. Then find .env file and configure database detail like following:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db name
DB_USERNAME=db user name
DB_PASSWORD=db password

Step 3 – Installing Laravel Yajra DataTables

In step 3, Navigate to your downloaded LaravelAjaxCRUDImageUpload directory. And then install Yajra Datatables Packages in your laravel 8. Open terminal and run the following command:

cd / LaravelAjaxCRUDImageUpload

composer require yajra/laravel-datatables-oracle
config/app.php

 'providers' => [
   
   Yajra\Datatables\DatatablesServiceProvider::class,
],

 'aliases' => [

  'Datatables' => Yajra\Datatables\Facades\Datatables::class,
] 

Then publish laravel datatables vendor package by using the following command:

php artisan vendor:publish

Step 4 – Create Model and Migration

In step 4, create book model and migration file by using the following command:

php artisan make:model Book -m

The above command will create two files into your laravel 8 ajax crud with image upload and datatable, ajax modal app, which is located inside the following locations:

  • LaravelAjaxCRUDImageUpload/app/Models/Book.php
  • LaravelAjaxCRUDImageUpload/database/migrations/create_books_table.php

Now, open Book.php model file inside LaravelAjaxCRUDImageUpload/app/Models directory. And open it then add the fillable property code into Book.php file, like following:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;

    protected $fillable = [
        'title', 'code', 'author', 'image'
    ];
}

Then, find create_books_table.php file inside LaravelAjaxCRUDImageUpload/database/migrations/ directory. Then open this file and add the following code into function up() on this file:

    public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('code');
            $table->string('author');
           $table->string('image');
            $table->timestamps();
        });
    }

Step 5 – Run Migration

Now, open again your terminal and type the following command on cmd to create tables into your selected database:

php artisan migrate

Step 6 – Create Routes

In step 6, open your web.php file, which is located inside routes directory. Then add the following routes into web.php file:

use App\Http\Controllers\AjaxCRUDImageController;

Route::get('ajax-crud-image-upload', [AjaxCRUDImageController::class, 'index']);
Route::post('add-update-book', [AjaxCRUDImageController::class, 'store']);
Route::post('edit-book', [AjaxCRUDImageController::class, 'edit']);
Route::post('delete-book', [AjaxCRUDImageController::class, 'destroy']);

Step 7 – Creating Datatables Controller

In step 7, create ajax crud datatable controller by using the following command:

php artisan make:controller AjaxCRUDImageController

The above command will create AjaxCRUDImageController.php file, which is located inside LaravelAjaxCRUDImageUpload/app/Http/Controllers/ directory. So add the following code into it:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Book;

use Datatables;

class AjaxCRUDImageController extends Controller
{
	/**
	 * Display a listing of the resource.
	 *
	 * @return \Illuminate\Http\Response
	 */
	public function index()
	{
	    if(request()->ajax()) {
	        return datatables()->of(Book::select('*'))
	        ->addColumn('action', 'book-action')
	        ->addColumn('image', 'show-image')
	        ->rawColumns(['action','image'])
	        ->addIndexColumn()
	        ->make(true);
	    }
	    return view('book-list');
	}
	 
	 
	/**
	 * Store a newly created resource in storage.
	 *
	 * @param  \Illuminate\Http\Request  $request
	 * @return \Illuminate\Http\Response
	 */
	public function store(Request $request)
	{  

	    $bookId = $request->id;

	    if($bookId){
             
            $book = Book::find($bookId);

	        if($request->hasFile('image')){
	            $path = $request->file('image')->store('public/images');
	            $book->image = $path;
	        }   
	     }else{
	     	   $path = $request->file('image')->store('public/images');
               $book = new Book;
               $book->image = $path;
	     }
	     
	    $book->title = $request->title;
        $book->code = $request->code;
        $book->author = $request->author;
        $book->save();
     
	    return Response()->json($book);
	}
	 
	 
	/**
	 * Show the form for editing the specified resource.
	 *
	 * @param  \App\book  $book
	 * @return \Illuminate\Http\Response
	 */
	public function edit(Request $request)
	{   
	    $where = array('id' => $request->id);
	    $book  = Book::where($where)->first();
	 
	    return Response()->json($book);
	}
	 
	 
	/**
	 * Remove the specified resource from storage.
	 *
	 * @param  \App\book  $book
	 * @return \Illuminate\Http\Response
	 */
	public function destroy(Request $request)
	{
	    $book = Book::where('id',$request->id)->delete();
	 
	    return Response()->json($book);
	}
}

Step 8 – Create Action Button(delete and edit) Blade View

In step 8, create action button name book-action.blade.php file. And add the following code into it:

<a href="javascript:void(0)" data-toggle="tooltip"  data-id="{{ $id }}" data-original-title="Edit" class="edit btn btn-success edit">
	Edit
</a>
<a href="javascript:void(0);" id="delete-book" data-toggle="tooltip" data-original-title="Delete" data-id="{{ $id }}" class="delete btn btn-danger">
	Delete
</a>

Step 9 – Show Image in Datatable

In step 9, create image display blade view named image.blade.php. Using this file, you can show image in datatable list. So add the following code into image.blade.php:

@if($image)
<img src="{{ Storage::url($image) }}" height="75" width="75" alt="" />
@else
<img src="https://www.riobeauty.co.uk/images/product_image_not_found.gif" alt="" height="75" width="75">
@endif

Step 10 – Create DataTable Blade View

In step 10, create new blade view file that named book-list.blade.php inside resources/views directory for display list using yajra datatables in laravel.

So, add the following code into book-list.blade.php file:

<!DOCTYPE html>
<html>
<head>
  <title>Laravel 8 DataTable Ajax Books CRUD Example</title>

  <meta name="csrf-token" content="{{ csrf_token() }}">

  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

  <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

  <link  href="https://cdn.datatables.net/1.10.21/css/jquery.dataTables.min.css" rel="stylesheet">

  <script src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script>

</head>
<body>

<div class="container mt-4">
  
  <div class="col-md-12 mt-1 mb-2"><button type="button" id="addNewBook" class="btn btn-success">Add</button></div>

  <div class="card">

    <div class="card-header text-center font-weight-bold">
      <h2>Laravel 8 Ajax Book CRUD with DataTable Example Tutorial</h2>
    </div>

    <div class="card-body">

        <table class="table table-bordered" id="datatable-ajax-crud">
           <thead>
              <tr>
                 <th>Id</th>
                 <th>Image</th>
                 <th>Book Title</th>
                 <th>Code</th>
                 <th>Author</th>
                 <th>Created at</th>
                 <th>Action</th>
              </tr>
           </thead>
        </table>

    </div>

  </div>
  <!-- boostrap add and edit book model -->
    <div class="modal fade" id="ajax-book-model" aria-hidden="true">
      <div class="modal-dialog modal-lg">
        <div class="modal-content">
          <div class="modal-header">
            <h4 class="modal-title" id="ajaxBookModel"></h4>
          </div>
          <div class="modal-body">
            <form action="javascript:void(0)" id="addEditBookForm" name="addEditBookForm" class="form-horizontal" method="POST" enctype="multipart/form-data">
              <input type="hidden" name="id" id="id">
              <div class="form-group">
                <label for="name" class="col-sm-2 control-label">Book Name</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="title" name="title" placeholder="Enter Book Name" maxlength="50" required="">
                </div>
              </div>  

              <div class="form-group">
                <label for="name" class="col-sm-2 control-label">Book Code</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="code" name="code" placeholder="Enter Book Code" maxlength="50" required="">
                </div>
              </div>

              <div class="form-group">
                <label class="col-sm-2 control-label">Book Author</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="author" name="author" placeholder="Enter author Name" required="">
                </div>
              </div>             

               <div class="form-group">
                <label class="col-sm-2 control-label">Book Image</label>
                <div class="col-sm-6 pull-left">
                  <input type="file" class="form-control" id="image" name="image" required="">
                </div>               
                <div class="col-sm-6 pull-right">
                  <img id="preview-image" src="https://www.riobeauty.co.uk/images/product_image_not_found.gif"
                        alt="preview image" style="max-height: 250px;">
                </div>
              </div>

              <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-primary" id="btn-save" value="addNewBook">Save changes
                </button>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            
          </div>
        </div>
      </div>
    </div>
<!-- end bootstrap model -->

<script type="text/javascript">
     
 $(document).ready( function () {

    $.ajaxSetup({
        headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        }
    });

    $('#image').change(function(){
           
    let reader = new FileReader();

    reader.onload = (e) => { 

      $('#preview-image').attr('src', e.target.result); 
    }

    reader.readAsDataURL(this.files[0]); 
  
   });

    $('#datatable-ajax-crud').DataTable({
           processing: true,
           serverSide: true,
           ajax: "{{ url('ajax-datatable-crud') }}",
           columns: [
                    {data: 'id', name: 'id', 'visible': false},
                    { data: 'image', name: 'image' , orderable: false},
                    { data: 'title', name: 'title' },
                    { data: 'code', name: 'code' },
                    { data: 'author', name: 'author' },
                    { data: 'created_at', name: 'created_at' },
                    {data: 'action', name: 'action', orderable: false},
                 ],
          order: [[0, 'desc']]
    });


    $('#addNewBook').click(function () {
       $('#addEditBookForm').trigger("reset");
       $('#ajaxBookModel').html("Add Book");
       $('#ajax-book-model').modal('show');
       $("#image").attr("required", "true");
       $('#id').val('');
       $('#preview-image').attr('src', 'https://www.riobeauty.co.uk/images/product_image_not_found.gif');


    });
 
    $('body').on('click', '.edit', function () {

        var id = $(this).data('id');
         
        // ajax
        $.ajax({
            type:"POST",
            url: "{{ url('edit-book') }}",
            data: { id: id },
            dataType: 'json',
            success: function(res){
              $('#ajaxBookModel').html("Edit Book");
              $('#ajax-book-model').modal('show');
              $('#id').val(res.id);
              $('#title').val(res.title);
              $('#code').val(res.code);
              $('#author').val(res.author);
              $('#image').removeAttr('required');

           }
        });

    });

    $('body').on('click', '.delete', function () {

       if (confirm("Delete Record?") == true) {
        var id = $(this).data('id');
         
        // ajax
        $.ajax({
            type:"POST",
            url: "{{ url('delete-book') }}",
            data: { id: id },
            dataType: 'json',
            success: function(res){

              var oTable = $('#datatable-ajax-crud').dataTable();
              oTable.fnDraw(false);
           }
        });
       }

    });

   $('#addEditBookForm').submit(function(e) {

     e.preventDefault();
  
     var formData = new FormData(this);
  
     $.ajax({
        type:'POST',
        url: "{{ url('add-update-book')}}",
        data: formData,
        cache:false,
        contentType: false,
        processData: false,
        success: (data) => {
          $("#ajax-book-model").modal('hide');
          var oTable = $('#datatable-ajax-crud').dataTable();
          oTable.fnDraw(false);
          $("#btn-save").html('Submit');
          $("#btn-save"). attr("disabled", false);
        },
        error: function(data){
           console.log(data);
         }
       });
   });
});
</script>
</div>  
</body>
</html>

Demonstration of above book-list.blade.php file code,

The following jQuery and ajax code into book-list.blade.php to get data from database table and display with html table with pagination:

    $('#datatable-ajax-crud').DataTable({
           processing: true,
           serverSide: true,
           ajax: "{{ url('ajax-datatable-crud') }}",
           columns: [
                    {data: 'id', name: 'id', 'visible': false},
                    { data: 'image', name: 'image' , orderable: false},
                    { data: 'title', name: 'title' },
                    { data: 'code', name: 'code' },
                    { data: 'author', name: 'author' },
                    { data: 'created_at', name: 'created_at' },
                    {data: 'action', name: 'action', orderable: false},
                 ],
          order: [[0, 'desc']]
    });

And the following code add, edit, delete data using ajax with datatable on book-list.blade.php file:

    $('#addNewBook').click(function () {
       $('#addEditBookForm').trigger("reset");
       $('#ajaxBookModel').html("Add Book");
       $('#ajax-book-model').modal('show');
       $("#image").attr("required", "true");
       $('#id').val('');
       $('#preview-image').attr('src', 'https://www.riobeauty.co.uk/images/product_image_not_found.gif');


    });
 
    $('body').on('click', '.edit', function () {

        var id = $(this).data('id');
         
        // ajax
        $.ajax({
            type:"POST",
            url: "{{ url('edit-book') }}",
            data: { id: id },
            dataType: 'json',
            success: function(res){
              $('#ajaxBookModel').html("Edit Book");
              $('#ajax-book-model').modal('show');
              $('#id').val(res.id);
              $('#title').val(res.title);
              $('#code').val(res.code);
              $('#author').val(res.author);
              $('#image').removeAttr('required');

           }
        });

    });

    $('body').on('click', '.delete', function () {

       if (confirm("Delete Record?") == true) {
        var id = $(this).data('id');
         
        // ajax
        $.ajax({
            type:"POST",
            url: "{{ url('delete-book') }}",
            data: { id: id },
            dataType: 'json',
            success: function(res){

              var oTable = $('#datatable-ajax-crud').dataTable();
              oTable.fnDraw(false);
           }
        });
       }

    });

   $('#addEditBookForm').submit(function(e) {

     e.preventDefault();
  
     var formData = new FormData(this);
  
     $.ajax({
        type:'POST',
        url: "{{ url('add-update-book')}}",
        data: formData,
        cache:false,
        contentType: false,
        processData: false,
        success: (data) => {
          $("#ajax-book-model").modal('hide');
          var oTable = $('#datatable-ajax-crud').dataTable();
          oTable.fnDraw(false);
          $("#btn-save").html('Submit');
          $("#btn-save"). attr("disabled", false);
        },
        error: function(data){
           console.log(data);
         }
       });
   });

And the ollowing code will display add book and edit book model:

  <!-- boostrap add and edit book model -->
    <div class="modal fade" id="ajax-book-model" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h4 class="modal-title" id="ajaxBookModel"></h4>
          </div>
          <div class="modal-body">
            <form action="javascript:void(0)" id="addEditBookForm" name="addEditBookForm" class="form-horizontal" method="POST">
              <input type="hidden" name="id" id="id">
              <div class="form-group">
                <label for="name" class="col-sm-2 control-label">Book Name</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="title" name="title" placeholder="Enter Book Name" maxlength="50" required="">
                </div>
              </div>  

              <div class="form-group">
                <label for="name" class="col-sm-2 control-label">Book Code</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="code" name="code" placeholder="Enter Book Code" maxlength="50" required="">
                </div>
              </div>

              <div class="form-group">
                <label class="col-sm-2 control-label">Book Author</label>
                <div class="col-sm-12">
                  <input type="text" class="form-control" id="author" name="author" placeholder="Enter author Name" required="">
                </div>
              </div>

              <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-primary" id="btn-save" value="addNewBook">Save changes
                </button>
              </div>
            </form>
          </div>
          <div class="modal-footer">
            
          </div>
        </div>
      </div>
    </div>
<!-- end bootstrap model -->

And the following jquery code will show image preview before upload:

    $('#image').change(function(){
           
    let reader = new FileReader();

    reader.onload = (e) => { 

      $('#preview-image').attr('src', e.target.result); 
    }

    reader.readAsDataURL(this.files[0]); 
  
   });

Don’t worry i have already added the jquery datatables libraries and ajax code on book-list.blade.php.

Step 11 – Start Development Server

In step 10, open cmd and run the following command:

php artisan serve

Then open browser and fire the following url into your browser:

http://127.0.0.1:8000/ajax-crud-image-upload

Laravel 8 ajax datatable crud with image upload and preview app will look like in the following image:

Leave a Comment