Draggable Bootstrap grid with order saving

A draggable Bootstrap grid that will save the order for future usage. The drag feature is implemented with gridstrap.js.

The concept being on page load get the grid order from the database via an Ajax GET call and then on dragging (interacting with #basic-grid) the new grid order is sent to the database via an Ajax POST.

CodePen example link.

Draggable grid with order saving

For persistence, MySQL is used with PHP. See the code at the bottom of this page.

The javascript used is stock standard and seen here before, except for this function:

function moveElement(move, toBeBefore) {
  $(move).insertBefore(toBeBefore);
}

This moves an element before another stated element. It is this function that is used on page load to move the grid around to the saved order. This is done before gridstrap.js is initialized with:

function gridDragInit() {
  $("#basic-grid").gridstrap();
}

The full functions:

$(document).ready(function () {
  getOrder();
});

function moveElement(move, toBeBefore) {
  $(move).insertBefore(toBeBefore);
}

function getOrder() {
  $.ajax({
    type: "GET",
    url: "https://peachpuff.srv3r.com/api/index.php",
    data: { drag_grid: "" },
    success: function (data) {
      //console.log(data[0]["element"]);
      moveElement(data[2]["element"], data[3]["element"]); //3 before 4
      moveElement(data[1]["element"], data[2]["element"]); //2 before 3
      moveElement(data[0]["element"], data[1]["element"]); //1 before 2
      setTimeout(gridDragInit(), 2);
    }
  });
}

function gridDragInit() {
  $("#basic-grid").gridstrap();
}

function updateOrder(number, element) {
  $.ajax({
    type: "POST",
    url: "https://peachpuff.srv3r.com/api/index.php",
    data: { drag_grid: "", number: number, element: element },
    success: function (result) {
      console.log(result);
    }
  });
}

function currentOrder() {
  var listItems = document.querySelector("#basic-grid").children;
  var listArray = Array.from(listItems);
  var counter = 0;
  listArray.forEach((item) => {
    counter++;
    if (item.id.includes("col")) {
      updateOrder(counter, "#" + item.id);
      //console.log(item.id + " " + counter);
    }
  });
}

The HTML (includes gridstrap.js):

<head>
    <title>Draggable grid</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/css/bootstrap.min.css"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://rosspi.github.io/gridstrap.js/jquery.gridstrap.js"></script>
</head>
<div class="container">
  <div id="basic-grid" class="row text-center" onclick="currentOrder();">
    <div class="col-xs-12 col-sm-6 col-md-3 col1" id="col1">Blue col1</div>
    <div class="col-xs-12 col-sm-6 col-md-3 col2" id="col2">Red col2</div>
    <div class="col-xs-12 col-sm-6 col-md-3 col3" id="col3">Green col3</div>
    <div class="col-xs-12 col-sm-6 col-md-3 col4" id="col4">Orange col4</div>
  </div>
  <p class="text-center mt-2">Draggable grid that saves order</p>
</div>

The CSS styling:

div:hover {
  cursor: grab;
}

.col1,
.col2,
.col3,
.col4 {
  color: white;
  padding: 1.5rem;
}
.col1 {
  background-color: blue;
}
.col2 {
  background-color: red;
}
.col3 {
  background-color: green;
}
.col4 {
  background-color: orange;
}

.gridstrap-cell-visible {
  position: absolute !important;
  transition: width 0.2s, height 0.2s, left 0.2s, top 0.2s;
}
.gridstrap-cell-hidden {
  opacity: 0;
  pointer-events: none;
  touch-action: none;
}
.gridstrap-cell-drag {
  transition: width 50ms, height 50ms, left 50ms, top 50ms;
  z-index: 10000;
}
.gridstrap-cell-resize {
  transition: width 50ms, height 50ms, left 50ms, top 50ms;
  z-index: 10000;
}
.gridstack-noncontiguous {
  opacity: 0;
}

api/index.php file:

<?php
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');

$db = new PDO('mysql:host=127.0.0.1;dbname=DATABASE;charset=utf8mb4', 'USERNAME', 'PASSWORD');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_POST['drag_grid'])) {
        $update = $db->prepare("UPDATE `drag_grid` SET `number` = ? WHERE `element` = ? LIMIT 1;");
        $update->execute([$_POST['number'], $_POST['element']]);
        echo json_encode($_POST);
    } else {
        echo json_encode(array());
    }
} elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
    if (isset($_GET['drag_grid'])) {
        $select = $db->prepare("SELECT * FROM `drag_grid` ORDER BY `number` ASC LIMIT 4;");
        $select->execute();
        echo json_encode($select->fetchAll(PDO::FETCH_ASSOC));
    } else {
        echo json_encode(array());
    }
} else {
    echo json_encode(array());
}

MySQL table:

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


-- Dumping database structure for api
CREATE DATABASE IF NOT EXISTS `api` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `api`;

-- Dumping structure for table api.drag_grid
CREATE TABLE IF NOT EXISTS `drag_grid` (
  `number` int(11) DEFAULT NULL,
  `element` varchar(50) NOT NULL,
  PRIMARY KEY (`element`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

-- Dumping data for table api.drag_grid: ~4 rows (approximately)
/*!40000 ALTER TABLE `drag_grid` DISABLE KEYS */;
INSERT INTO `drag_grid` (`number`, `element`) VALUES
  (1, '#col1'),
  (2, '#col2'),
  (3, '#col3'),
  (4, '#col4');
/*!40000 ALTER TABLE `drag_grid` ENABLE KEYS */;

/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

 

 

Video