<!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">
  <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>
          &nbsp;&nbsp;
          <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>
          &nbsp;
          <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>
          &nbsp;&nbsp;
          <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>
          &nbsp;
          <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() {
  // call fetchData function
  fetchData();
  
  
  // function to fetch data from database
 //(VERSION to avoid php and the mysql query)
  function fetchData() {
    $.ajax({
      url: '/ajax/arrays.txt',
      dataType: "json",
      success: function(response) {
        table.clear().draw();
        table.rows.add( response.data ).draw();
        table.searchPanes.rebuildPane();
      }
    })
  }
  
  // function to fetch data from database
  //(VERSION OF MY PROJECT CALLING PHP -> DB REQUEST)
  /*
  function fetchData() {
    $.ajax({
      url: "server.php?action=fetchData",
      type: "POST",
      dataType: "json",
      success: function(response) {
        var data = response.data;
        table.clear().draw();
        $.each(data, function(index, value) {
          table.row.add([
            value.id,
            value.first_name,
            value.last_name,
            '<img src="uploads/' + value.image + '" style="width:40px; height:40px; border:1px solid gray; border-radius:5px; object-fit:cover">',
            value.email,
            value.country,
            value.gender,
            '<Button type="button" class="btn btn-primary btn-sm editBtn" value="' + value.id + '"><i class="fa-solid fa-pen-to-square"></i></Button>' +
            '<Button type="button" class="btn btn-danger btn-sm deleteBtn" value="' + value.id + '"><i class="fa-solid fa-trash"></i></Button>' +
            '<input type="hidden" class="delete_image" value="' + value.image + '">'
          ]).draw(false);
        })
      }
    })
  }
*/
            
            
            
  
  
  
  //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');
      }
  });
});
1 error
Line 18: Missing semicolon.
Output 300px

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
anonymouspro
0viewers