In this tutorial, you will learn how to create or develop a PHP CRUD Operations w/o Pagre Refresh/Reloading using Ajax and DataTables. Here, we will enlist the data from the database using the server-side processing of DataTables. This tutorial is helpful especially for optimizing the page load of your future PHP Project.
The main goal of the simple web app that we will be creating is to display the data/records from the database into a table using DataTables which means it has a sort, filter, limit, and pagination functions. We will be using Ajax to process the new, updated, and delete data. Lastly, in each process, the table must update its data without leaving the current page/reloading/refreshing.
In this tutorial, I will be using the following
- XAMPP as my local web-server to run my PHP scripts.
- Bootstrap 5 for the user interface or the design of the web app
- jQuery to use Ajax
- DataTables andd please include the Button Extention
Compile the plugins/libraries files in a single foleder in your XAMPP's htdocs directory. Please open your XAMPP's Control Panel and start the Apache and MySQL.
Creating the Database
In your web browser, browse the PHPMyAdmin i.e. http://localhost/phpmyadmin
and create a new database naming dummy_db. Then navigate to the database SQL Tab and paster the SQL Script below to create our database table and columns.
In you source code folder, create a new PHP file naming connect.php. Copy/Paste the script below. The script will create a connection to our database.
<?php $host = "localhost"; $username = "root"; $password = ""; $database = "dummy_db"; $conn = new mysqli($host, $username, $password, $database); if(!$conn){ echo "Database connection failed. Error:".$conn->error; exit; } ?>
Creating the Interface
Create a new PHP file naming index.php. Paste the following script, to create our web app's interface. Please make sure that plugins/libraries path are correct in your end for both CSS Links and External JavaScript.
<!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.0"> <link rel="stylesheet" href="css/bootstrap.css"> <link rel="stylesheet" href="DataTables/datatables.min.css"> <link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.0.0/css/buttons.dataTables.min.css"> <style> button.dt-button.btn-primary{ background:var(--bs-primary)!important; color:white; } </style> </head> <body class=""> <nav class="navbar navbar-expand-lg navbar-light bg-dark bg-gradient"> <div class="container"> </div> </nav> <div class="container py-5 h-100"> <div class="row"> <div class="col-lg-12"> </div> </div> <hr> <div class="row"> </div> <div class="row"> <div class="col-lg-12"> <table class="table table-hover table-bordered table-striped" id="authors-tbl"> <thead> <tr class="bg-dark text-light bg-gradient bg-opacity-150"> </tr> </thead> <tfoot> <tr class="bg-dark text-light bg-gradient bg-opacity-150"> </tr> </tfoot> </table> </div> </div> </div> <!-- Add Modal --> <div class="modal fade" id="add_modal" data-bs-backdrop="static"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> </div> <div class="modal-body"> <div class="container-fluid"> <form action="" id="new-author-frm"> <div class="form-group"> <input type="text" class="form-control rounded-0" id="first_name" name="first_name" required> </div> <div class="form-group"> <input type="text" class="form-control rounded-0" id="last_name" name="last_name" required> </div> <div class="form-group"> <input type="text" class="form-control rounded-0" id="email" name="email" required> </div> <div class="form-group"> <input type="date" class="form-control rounded-0" id="birthdate" name="birthdate" required> </div> </form> </div> </div> <div class="modal-footer"> </div> </div> </div> </div> <!-- /Add Modal --> <!-- Edit Modal --> <div class="modal fade" id="edit_modal" data-bs-backdrop="static"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> </div> <div class="modal-body"> <div class="container-fluid"> <form action="" id="edit-author-frm"> <input type="hidden" name="id"> <div class="form-group"> <input type="text" class="form-control rounded-0" id="first_name" name="first_name" required> </div> <div class="form-group"> <input type="text" class="form-control rounded-0" id="last_name" name="last_name" required> </div> <div class="form-group"> <input type="text" class="form-control rounded-0" id="email" name="email" required> </div> <div class="form-group"> <input type="date" class="form-control rounded-0" id="birthdate" name="birthdate" required> </div> </form> </div> </div> <div class="modal-footer"> </div> </div> </div> </div> <!-- /Edit Modal --> <!-- Delete Modal --> <div class="modal fade" id="delete_modal" data-bs-backdrop="static"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> </div> <div class="modal-body"> <div class="container-fluid"> <form action="" id="delete-author-frm"> <input type="hidden" name="id"> </form> </div> </div> <div class="modal-footer"> </div> </div> </div> </div> <!-- /Delete Modal --> </body> </html>
The script below contains all of the scripts and functions that initiating the processes of the CRUD Operations. It also includes the DataTables initiation. Save the file as script.js. In my case, the file is located inside the js directory inside my source code folder.
var authorsTbl = ''; $(function() { // draw function [called if the database updates] function draw_data() { if ($.fn.dataTable.isDataTable('#authors-tbl') && authorsTbl != '') { authorsTbl.draw(true) } else { load_data(); } } function load_data() { authorsTbl = $('#authors-tbl').DataTable({ dom: '<"row"B>flr<"py-2 my-2"t>ip', "processing": true, "serverSide": true, "ajax": { url: "./get_authors.php", method: 'POST' }, columns: [{ data: 'id', className: 'py-0 px-1' }, { data: 'first_name', className: 'py-0 px-1' }, { data: 'last_name', className: 'py-0 px-1' }, { data: 'email', className: 'py-0 px-1' }, { data: 'birthdate', className: 'py-0 px-1' }, { data: null, orderable: false, className: 'text-center py-0 px-1', render: function(data, type, row, meta) { console.log() return '<a class="me-2 btn btn-sm rounded-0 py-0 edit_data btn-primary" href="javascript:void(0)" data-id="' + (row.id) + '">Edit</a><a class="btn btn-sm rounded-0 py-0 delete_data btn-danger" href="javascript:void(0)" data-id="' + (row.id) + '">Delete</a>'; } } ], drawCallback: function(settings) { $('.edit_data').click(function() { $.ajax({ url: 'get_single.php', data: { id: $(this).attr('data-id') }, method: 'POST', dataType: 'json', error: err => { alert("An error occured while fetching single data") }, success: function(resp) { if (!!resp.status) { Object.keys(resp.data).map(k => { if ($('#edit_modal').find('input[name="' + k + '"]').length > 0) $('#edit_modal').find('input[name="' + k + '"]').val(resp.data[k]) }) $('#edit_modal').modal('show') } else { alert("An error occured while fetching single data") } } }) }) $('.delete_data').click(function() { $.ajax({ url: 'get_single.php', data: { id: $(this).attr('data-id') }, method: 'POST', dataType: 'json', error: err => { alert("An error occured while fetching single data") }, success: function(resp) { if (!!resp.status) { $('#delete_modal').find('input[name="id"]').val(resp.data['id']) $('#delete_modal').modal('show') } else { alert("An error occured while fetching single data") } } }) }) }, buttons: [{ text: "Add New", className: "btn btn-primary py-0", action: function(e, dt, node, config) { $('#add_modal').modal('show') } }], "order": [ [1, "asc"] ], initComplete: function(settings) { $('.paginate_button').addClass('p-1') } }); } //Load Data load_data() //Saving new Data $('#new-author-frm').submit(function(e) { e.preventDefault() $('#add_modal button').attr('disabled', true) $('#add_modal button[form="new-author-frm"]').text("saving ...") $.ajax({ url: 'save_data.php', data: $(this).serialize(), method: 'POST', dataType: "json", error: err => { alert("An error occured. Please chech the source code and try again") }, success: function(resp) { if (!!resp.status) { if (resp.status == 'success') { var _el = $('<div>') _el.hide() _el.addClass('alert alert-primary alert_msg') _el.text("Data successfulle saved"); $('#new-author-frm').get(0).reset() $('.modal').modal('hide') $('#msg').append(_el) _el.show('slow') draw_data(); setTimeout(() => { _el.hide('slow') .remove() }, 2500) } else if (resp.status == 'success' && !!resp.msg) { var _el = $('<div>') _el.hide() _el.addClass('alert alert-danger alert_msg form-group') _el.text(resp.msg); $('#new-author-frm').append(_el) _el.show('slow') } else { alert("An error occured. Please chech the source code and try again") } } else { alert("An error occurred. Please check the source code and try again") } $('#add_modal button').attr('disabled', false) $('#add_modal button[form="new-author-frm"]').text("Save") } }) }) // Update Data $('#edit-author-frm').submit(function(e) { e.preventDefault() $('#edit_modal button').attr('disabled', true) $('#edit_modal button[form="edit-author-frm"]').text("saving ...") $.ajax({ url: 'update_data.php', data: $(this).serialize(), method: 'POST', dataType: "json", error: err => { alert("An error occured. Please chech the source code and try again") }, success: function(resp) { if (!!resp.status) { if (resp.status == 'success') { var _el = $('<div>') _el.hide() _el.addClass('alert alert-primary alert_msg') _el.text("Data successfulle updated"); $('#edit-author-frm').get(0).reset() $('.modal').modal('hide') $('#msg').append(_el) _el.show('slow') draw_data(); setTimeout(() => { _el.hide('slow') .remove() }, 2500) } else if (resp.status == 'success' && !!resp.msg) { var _el = $('<div>') _el.hide() _el.addClass('alert alert-danger alert_msg form-group') _el.text(resp.msg); $('#edit-author-frm').append(_el) _el.show('slow') } else { alert("An error occured. Please chech the source code and try again") } } else { alert("An error occurred. Please check the source code and try again") } $('#edit_modal button').attr('disabled', false) $('#edit_modal button[form="edit-author-frm"]').text("Save") } }) }) // DELETE Data $('#delete-author-frm').submit(function(e) { e.preventDefault() $('#delete_modal button').attr('disabled', true) $('#delete_modal button[form="delete-author-frm"]').text("deleting data ...") $.ajax({ url: 'delete_data.php', data: $(this).serialize(), method: 'POST', dataType: "json", error: err => { alert("An error occured. Please chech the source code and try again") }, success: function(resp) { if (!!resp.status) { if (resp.status == 'success') { var _el = $('<div>') _el.hide() _el.addClass('alert alert-primary alert_msg') _el.text("Data successfulle updated"); $('#delete-author-frm').get(0).reset() $('.modal').modal('hide') $('#msg').append(_el) _el.show('slow') draw_data(); setTimeout(() => { _el.hide('slow') .remove() }, 2500) } else if (resp.status == 'success' && !!resp.msg) { var _el = $('<div>') _el.hide() _el.addClass('alert alert-danger alert_msg form-group') _el.text(resp.msg); $('#delete-author-frm').append(_el) _el.show('slow') } else { alert("An error occured. Please chech the source code and try again") } } else { alert("An error occurred. Please check the source code and try again") } $('#delete_modal button').attr('disabled', false) $('#delete_modal button[form="delete-author-frm"]').text("YEs") } }) }) });
Creating Our PHP API's
The following PHP files are the codes that queries in our database. These are for fetching, adding, and deleting data in oue database. Save the files as the filename above each script.
get_authors.php
<?php require_once("./connect.php"); $totalCount = $conn->query("SELECT * FROM `authors` ")->num_rows; $search_where = ""; $search_where = " where "; $search_where .= " first_name LIKE '%{$search['value']}%' "; $search_where .= " OR last_name LIKE '%{$search['value']}%' "; $search_where .= " OR email LIKE '%{$search['value']}%' "; $search_where .= " OR date_format(birthdate,'%M %d, %Y') LIKE '%{$search['value']}%' "; } "first_name", "last_name", "email", "unix_timestamp(birthdate)"); $query = $conn->query("SELECT * FROM `authors` {$search_where} ORDER BY {$columns_arr[$order[0]['column']]} {$order[0]['dir']} limit {$length} offset {$start} "); $recordsFilterCount = $conn->query("SELECT * FROM `authors` {$search_where} ")->num_rows; $recordsTotal= $totalCount; $recordsFiltered= $recordsFilterCount; $i= 1 + $start; while($row = $query->fetch_assoc()){ $row['no'] = $i++; $data[] = $row; } 'recordsTotal'=>$recordsTotal, 'recordsFiltered'=>$recordsFiltered, 'data'=>$data ) );
save_data.php
<?php require_once('connect.php'); $query = $conn->query("INSERT INTO `authors` (`first_name`,`last_name`,`email`,`birthdate`) VALUE ('{$first_name}','{$last_name}','{$email}','{$birthdate}')"); if($query){ $resp['status'] = 'success'; }else{ $resp['status'] = 'failed'; $resp['msg'] = 'An error occured while saving the data. Error: '.$conn->error; }
get_single.php
<?php require_once('connect.php'); $query = $conn->query("SELECT * FROM `authors` where id = '{$id}'"); if($query){ $resp['status'] = 'success'; $resp['data'] = $query->fetch_array(); }else{ $resp['status'] = 'success'; $resp['error'] = 'An error occured while fetching the data. Error: '.$conn->error; }
update_data.php
<?php require_once('connect.php'); $update = $conn->query("UPDATE `authors` set `first_name` = '{$first_name}', `last_name` = '{$last_name}', `email` = '{$email}',`birthdate` = '{$birthdate}' where id = '{$id}'"); if($update){ $resp['status'] = 'success'; }else{ $resp['status'] = 'failed'; $resp['msg'] = 'An error occured while saving the data. Error: '.$conn->error; }
delete_data.php
<?php require_once('connect.php'); $delete = $conn->query("DELETE FROM `authors` where id = '{$id}'"); if($delete){ $resp['status'] = 'success'; }else{ $resp['status'] = 'failed'; $resp['msg'] = 'An error occured while saving the data. Error: '.$conn->error; }
There you go. You can now test the web application that we've created on your end. If there's an error occurred on your end. Please review the scripts above. You can also download the working source code I created. The download button is located below.
DEMO
That's the end of this tutorial. Leave a comment below for any questions. Explore more on this website for more Tutorials and Free Source Codes.