Keith

Drag And Drop Sortable List

by Keith Rowles • 04/11/2023JavaScript

Landscape of desert and stars in sky at night

Summary

Fun drag and drop sortable list using javascript, css and html.

Sort the list from 1 to 10. Top 10 NRL Teams in 2023.

Then check your answers by clicking on the check order button.

Note: The list is generated by javascript.

HTML

<h1>Top 10 NRL Teams 2023</h1>
<p>Drag and Drop Items to place in the correct order. From 1 to 10.</p>
<ul class="draggable-list" id="draggable-list"></ul>
<button class="check-btn" id="check">
  Check Order
  <i class="fas fa-paper-plane"></i>
</button>

CSS

@import url('https://fonts.googleapis.com/css?family=Lato&display=swap');

:root {
  --border-color: #e3e5e4;
  --background-color: #c3c7ca;
  --text-color: #34444f;
  --heading-color: dodgerblue;
  --text-color-white: white;
}

* {
  box-sizing: border-box;
}

body {
  background-color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  height: 100vh;
  margin: 0;
  font-family: 'Lato', sans-serif;
}
h1 {
  color: var(--heading-color);
}

.draggable-list {
  border: 1px solid var(--border-color);
  color: var(--text-color);
  padding: 0;
  list-style-type: none;
}

.draggable-list li {
  background-color: #fff;
  display: flex;
  flex: 1;
}

.draggable-list li:not(:last-of-type) {
  border-bottom: 1px solid var(--border-color);
}

.draggable-list .number {
  background-color: var(--heading-color);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  height: 60px;
  width: 60px;
  color: var(--text-color-white);
}

.draggable-list li.over .draggable {
  background-color: #b4b4b4;
}

.draggable-list .person-name {
  margin: 0 20px 0 0;
}

.draggable-list li.right .person-name {
  color: #3ae374;
}

.draggable-list li.wrong .person-name {
  color: #ff3838;
}

.draggable {
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px;
  flex: 1;
}

.check-btn {
  background-color: var(--heading-color);
  border: none;
  color: var(--text-color-white);
  font-size: 16px;
  padding: 10px 20px;
  cursor: pointer;
  border-radius: 5px;
}
.check-btn:hover {
  background-color: darkslategray;
}

.check-btn:active {
  transform: scale(0.98);
}

.check-btn:focus {
  outline: none;
}

JavaScript

const draggable_list = document.getElementById('draggable-list');
const check = document.getElementById('check');

const nrlteams = [
  'Penrith Panthers',
  'Brisbane Broncos',
  'Melbourne Storm',
  'New Zealand Warriors',
  'New Castle Knights',
  'Cronulla Sharks',
  'Easts Roosters',
  'Canberra Raiders',
  'Souths Rabbitohs',
  'Paramatta Eels',
];

// store the list items
const listItems = [];

let dragStartIndex;

createList();

// insert list items into dom
function createList() {
  [...nrlteams]
    .map((a) => ({ value: a, sort: Math.random() }))
    .sort((a, b) => a.sort - b.sort)
    .map((a) => a.value)
    .forEach((person, index) => {
      const listItem = document.createElement('li');
      listItem.setAttribute('data-index', index);
      listItem.innerHTML = `
        <span class="number">${index + 1}</span>
        <div class="draggable" draggable="true">
            <p class="person-name">${person}</p>
            <i class="fas fa-grip-lines"></i>
        </div>
        `;

      listItems.push(listItem);

      draggable_list.appendChild(listItem);
    });

  addEventListeners();
}

function dragStart() {
  //   console.log('Event: ', 'dragstart');
  dragStartIndex = +this.closest('li').getAttribute('data-index');
  console.log(dragStartIndex);
}
function dragEnter() {
  //   console.log('Event: ', 'dragenter');
  this.classList.add('over');
}
function dragLeave() {
  //   console.log('Event: ', 'dragleave');
  this.classList.remove('over');
}
function dragOver(e) {
  //   console.log('Event: ', 'dragover');
  e.preventDefault();
}
function dragDrop() {
  //   console.log('Event: ', 'drop');
  const dragEndIndex = +this.getAttribute('data-index');
  swapItems(dragStartIndex, dragEndIndex);
  this.classList.remove('over');
}
// swap list items
function swapItems(fromIndex, toIndex) {
  const itemOne = listItems[fromIndex].querySelector('.draggable');
  const itemTwo = listItems[toIndex].querySelector('.draggable');
  console.log(itemOne, itemTwo);

  listItems[fromIndex].appendChild(itemTwo);
  listItems[toIndex].appendChild(itemOne);
}

// check the order of list items
function checkOrder() {
  listItems.forEach((listItem, index) => {
    const personName = listItem.querySelector('.draggable').innerText.trim();

    if (personName !== nrlteams[index]) {
      listItem.classList.add('wrong');
    } else {
      listItem.classList.remove('wrong');
      listItem.classList.add('right');
    }
  });
}

function addEventListeners() {
  const draggables = document.querySelectorAll('.draggable');
  const dragListItems = document.querySelectorAll('.draggable-list li');

  draggables.forEach((draggable) => {
    draggable.addEventListener('dragstart', dragStart);
  });

  dragListItems.forEach((item) => {
    item.addEventListener('dragover', dragOver);
    item.addEventListener('drop', dragDrop);
    item.addEventListener('dragenter', dragEnter);
    item.addEventListener('dragleave', dragLeave);
  });
}

check.addEventListener('click', checkOrder);

Demo

Open demo on Code Pen.

Link to Demo