<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">
<title>PHP MySQL Ajax CRUD with Bootstrap 5 and Datatables Library</title>
<!-- JQUERY, doit être placé avant les scripts des plugins-->
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<!-- FONTAWESOME -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<!-- BOOTSTRAP -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<!-- DATATABLES -->
<script src="https://cdn.datatables.net/2.0.1/js/dataTables.min.js"></script>
<!-- DataTables style -->
<link href="https://cdn.datatables.net/2.0.1/css/dataTables.dataTables.min.css" rel="stylesheet">
<!-- DataTables plugins Styles-->
<link href="https://cdn.datatables.net/responsive/3.0.0/css/responsive.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/searchpanes/2.3.0/css/searchPanes.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/select/2.0.0/css/select.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/buttons/3.0.0/css/buttons.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/fixedheader/4.0.0/css/fixedHeader.dataTables.min.css" rel="stylesheet">
<!-- DataTables Plugins Scripts-->
<script src="https://cdn.datatables.net/responsive/3.0.0/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.0/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/searchpanes/2.3.0/js/dataTables.searchPanes.min.js"></script>
<script src="https://cdn.datatables.net/select/2.0.0/js/dataTables.select.min.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.0/js/buttons.html5.min.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.0/js/buttons.print.min.js"></script>
<script src="https://cdn.datatables.net/buttons/3.0.0/js/buttons.colVis.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/pdfmake.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/vfs_fonts.js"></script>
<script src="https://cdn.datatables.net/fixedheader/4.0.0/js/dataTables.fixedHeader.min.js"></script>
<!-- CSS -->
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav ></nav>
<div class="container">
<!-- Button to trigger Add user offcanvas -->
<div class="pb-3 pt-3">
<!--button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasAddUser"><i class="fa-solid fa-user-plus fa-xs"></i> Add new user</button-->
</div>
<table id="myTable" class="responsive nowrap hover row-border cell-border order-column compact" style="width:100%;">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th class="none">Salary</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<!-- Add user offcanvas -->
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasAddUser" style="width:700px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Add new user</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<form method="POST" id="insertForm">
<div class="row mb-3">
<div class="col">
<label class="form-label">First Name</label>
<input type="text" class="form-control" name="first_name" placeholder="Nikola">
</div>
<div class="col">
<label class="form-label">Last Name</label>
<input type="text" class="form-control" name="last_name" placeholder="Tesla">
</div>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" placeholder="name@example.com">
</div>
<div class="mb-3">
<label class="form-label">Country</label>
<select name="country" class="form-control">
<option value="Åland Islands">Åland Islands</option>
<option value="Albania">Albania</option>
<option value="Algeria">Algeria</option>
<option value="American Samoa">American Samoa</option>
<option value="Andorra">Andorra</option>
<option value="Angola">Angola</option>
<option value="Anguilla">Anguilla</option>
<option value="Antarctica">Antarctica</option>
<option value="Zimbabwe">Zimbabwe</option>
</select>
</div>
<div class="form-group mb-3">
<label class="form-label">Gender:</label>
<input type="radio" class="form-check-input" id="radio_gender_male" name="gender" value="male">
<label class="form-input-label" for="radio_gender_male">Male</label>
<input type="radio" class="form-check-input" id="radio_gender_female" name="gender" value="female">
<label class="form-input-label" for="radio_gender_female">Female</label>
</div>
<div>
<button type="submit" class="btn btn-primary me-1" id="insertBtn">Submit</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="offcanvas">Cancel</button>
</div>
</form>
</div>
</div>
<!-- Edit user offcanvas -->
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasEditUser" style="width:700px;">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Edit user data</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<form method="POST" id="editForm">
<input type="hidden" name="id" id="id">
<div class="row mb-3">
<div class="col">
<label class="form-label">First Name</label>
<input type="text" class="form-control" name="first_name" placeholder="Nikola">
</div>
<div class="col">
<label class="form-label">Last Name</label>
<input type="text" class="form-control" name="last_name" placeholder="Tesla">
</div>
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control" name="email" placeholder="name@example.com">
</div>
<div class="mb-3">
<label class="form-label">Country</label>
<select name="country" class="form-control">
<option value="Åland Islands">Åland Islands</option>
<option value="Albania">Albania</option>
<option value="Algeria">Algeria</option>
<option value="American Samoa">American Samoa</option>
<option value="Andorra">Andorra</option>
<option value="Angola">Angola</option>
<option value="Anguilla">Anguilla</option>
<option value="Antarctica">Antarctica</option>
<option value="Zimbabwe">Zimbabwe</option>
</select>
</div>
<div class="form-group mb-3">
<label class="form-label">Gender:</label>
<input type="radio" class="form-check-input" id="radio_gender_male" name="gender" value="male">
<label class="form-input-label" for="radio_gender_male">Male</label>
<input type="radio" class="form-check-input" id="radio_gender_female" name="gender" value="female">
<label class="form-input-label" for="radio_gender_female">Female</label>
</div>
<div>
<button type="submit" class="btn btn-primary me-1" id="editBtn">Update</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="offcanvas">Cancel</button>
</div>
</form>
</div>
</div>
<!-- Toast container -->
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<!-- Success toast -->
<div class="toast align-items-center text-bg-success" role="alert" aria-live="assertive" aria-atomic="true" id="successToast">
<div class="d-flex">
<div class="toast-body">
<strong>Success!</strong>
<span id="successMsg"></span>
</div>
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
<!-- Error toast -->
<div class="toast align-items-center text-bg-danger" role="alert" aria-live="assertive" aria-atomic="true" id="errorToast">
<div class="d-flex">
<div class="toast-body">
<strong>Error!</strong>
<span id="errorMsg"></span>
</div>
<button type="button" class="btn-close me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
</body>
</html>
body {
font: 90%/1.45em "Helvetica Neue", HelveticaNeue, Verdana, Arial, Helvetica, sans-serif;
margin: 0;
padding: 0;
color: #333;
background-color: #fff;
}
.dtsp-title {
display: none;
}
$(document).ready(function() {
//Fonction nécessaire aux datatables pour Masquer les en-têtes des colonnes masquées
function hideSearchInputs(columns) {
for (i=0; i<columns.length; i++) {
if (columns[i]) {
$('.filters th:eq(' + i + ')' ).show();
} else {
$('.filters th:eq(' + i + ')' ).hide();
}
}
}
//initialize datatables
$('#myTable thead tr').clone(true).addClass('filters').appendTo( '#myTable thead' );
var table = new DataTable('#myTable', {
ajax: '/ajax/arrays.txt',
orderCellsTop: true,
fixedHeader: {
headerOffset: 0
},
language: {
url: "https://cdn.datatables.net/plug-ins/2.0.1/i18n/fr-FR.json",
buttons: {
'copy': '<i class="fa-solid fa-copy"></i> Copier',
'print': '<i class="fa-solid fa-print"></i> Imprimer',
'excel': '<i class="fa-solid fa-file-excel"></i> Excel',
'pdf': '<i class="fa-solid fa-file-pdf"></i> PDF',
'colvis': 'Visibilité des colonnes'
},
searchPanes: {
collapseMessage: 'Masquer',
showMessage: 'Montrer',
clearMessage: 'Effacer les filtres',
title: {
"_": "%d filtres sélectionnés",
"0": "Aucun filtre en cours",
"1": "1 filtre sélectionné",
}
},
},
paging: true,
lengthChange: false,
searching: true,
ordering: true,
autoWidth: false,
responsive: true, // to hide detail rows whith class="none"
//stateSave: false,
//stateDuration: 0,
//select: {
// style: 'single' //api, single, multi, os, multi+shift
//},
layout: {
top1Start: {
buttons: [
{ text: '<i class="fa-solid fa-user-plus fa-xs"></i> Add new user',attr: {
'id': 'dtBtnoffcanvasAddUser',
'data-bs-toggle' : 'offcanvas',
'data-bs-target' : '#offcanvasAddUser',
},
},
{ text: '<i class="fa-solid fa-caret-down"></i> Show details', attr: { id: 'dtBtnShowChildren' },
action: function ( e, dt, node, config ) {
dt.rows(':not(.parent)').nodes().to$().find('td:first-child').trigger('click');
}
},
{ text: '<i class="fa-solid fa-caret-right"></i> Hide details', attr: { id: 'dtBtnHideChildren' },
action: function ( e, dt, node, config ) {
dt.rows('.parent').nodes().to$().find('td:first-child').trigger('click');
}
},
"copy",
//"print",
//"excel",
//"pdf",
//",colvis"
{ text: '<i class="fa-solid fa-file-export"></i> Exporter',
split: [ 'excel'/*, 'pdf' */],
fade: 100,
background:false
},
{
text: 'Filtres',
className: 'spToggle showPanes',
action: function (e, dt, node, config) {
dt.searchPanes.container().find('.dtsp-searchPanes').slideToggle(200, function () {
$('.spToggle').toggleClass('showPanes', $(this).is(':visible'));
});
},
},
{ text: '<i class="fa-solid fa-trash"></i> Clear search', attr: { id: 'dtBtnClearGlobalSearch' }}
],
},
top1End: {
search: {
placeholder: 'Recherche globale'
}
},
topEnd: null,
top: {
searchPanes: {
filterChanged: function (count) {
$('.spToggle').text(this.i18n('searchPanes.collapse', {0: 'Filtres (0)', _: 'Filtres (%d)'}, count));
},
collapse: false, // collapse/expand all buttons of SearchPanes
clear: true, // clear all button of SearchPanes
//initCollapsed: true
//layout: 'columns-6' // by default is auto, else use columns-x
//cascadePanes: true,
}
},
bottomEnd: {
paging: {
numbers: 10
}
},
},
columnDefs: [
{
searchPanes: {
show: true,
dtOpts: {
select:{
style: 'multi+shift'
},
//paging: false,
//pagingType: 'numbers',
searching: true,
}
},
targets: [0, 1, 2],
}
],
initComplete: function () {
var api = this.api();
// COLUMN FILTERS INTO HEADERS
// For each column, add a input search filter
api.columns([2, 3, 4]).eq(0).each(function(colIdx) {
// Set the header cell to contain the input element
var cell = $('.filters th').eq($(api.column(colIdx).header()).index());
var title = $(cell).text();
$(cell).html( '<input type="text" placeholder="Rechercher" />' );
// On every keypress in this input
$('input', $('.filters th').eq($(api.column(colIdx).header()).index()) )
.off('keyup change')
.on('keyup change', function (e) {
e.stopPropagation();
// Get the search value
$(this).attr('title', $(this).val());
var regexr = '({search})'; //$(this).parents('th').find('select').val();
var cursorPosition = this.selectionStart;
// Search the column for that value
api
.column(colIdx)
.search((this.value !== "") ? regexr.replace('{search}', '((('+this.value+')))') : "", this.value !== "", this.value === "")
.draw();
$(this).focus()[0].setSelectionRange(cursorPosition, cursorPosition);
});
});
// For each column, add a select filter
api.columns([0, 1]).eq(0).each(function(colIdx) {
// Set the header cell to contain the select element
var cell = $('.filters th').eq($(api.column(colIdx).header()).index());
var title = $(cell).text();
$(cell).html( '<select><option value=""</option></select>' );
// On every select action
//var column = this;
var column = api.column(colIdx);
var select = $('<select><option value=""</option></select>')
//.appendTo($(column.header()).empty())
.appendTo($(cell).empty())
.on('change', function() {
var val = $.fn.dataTable.util.escapeRegex(
$(this).val()
);
column
.search(val ? '^' + val + '$' : '', true, false)
.draw();
});
column.data().unique().sort().each(function(d, j) {
select.append('<option value="' + d + '">' + d + '</option>');
});
});
// Hide the cloned header of hidded columns
hideSearchInputs( api.columns().responsiveHidden().toArray() );
// Style SearchPanes class
$('div.dt-scroll-body table.dataTable', this.api().searchPanes.container()).addClass('responsive stripe nowrap hover row-border compact');
// Handle click on "Show details" button
$('#dtBtnShowChildren').on('click', function(){
// Expand row details
table.rows(':not(.dt-hasChild)').nodes().to$().find('td:first-child').trigger('click');
});
// Handle click on "Hide details" button
$('#dtBtnHideChildren').on('click', function(){
// Collapse row details
table.rows('.dt-hasChild').nodes().to$().find('td:first-child').trigger('click');
});
// Clear All searches by a click on button
$('#dtBtnClearGlobalSearch').on('click', function() {
// Clear table search
table.search('').columns().search('').draw();
// Clear columns input filters (into each header)
table.columns().eq(0).each(function(colIdx) {
var cell = $('.filters th').eq($(api.column(colIdx).header()).index());
$(cell).find('input').val('');
});
// Clear columns select filters (into each header)
table.columns().eq(0).each(function(colIdx) {
var cell = $('.filters th').eq($(api.column(colIdx).header()).index());
$('select', cell).val('');
});
// Clear SearchPanes selection
table.searchPanes.clearSelections();
//Hide SearchPanes
//table.searchPanes.container().find('.dtsp-searchPanes').css('display','none');
});
// Hide the "Clear All" button of SearchPanes, Hide to conserve individual clear button of each pane
$('.dtsp-clearAll').hide();
//Hide SearchPanes on initialization (collapsed before to be expand by button)
table.searchPanes.container().find('.dtsp-searchPanes').css('display','none');
//Hide SearchPanes title ("X filters active")
table.searchPanes.container().find('.dtsp-title').css('display','none');
}
});
});
You can jump to the latest bin by adding /latest
to your URL
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + [ | Indents selected lines |
ctrl + ] | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Clone Bin |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |