Skip to content

Instantly share code, notes, and snippets.

@nastanford
Created April 15, 2022 12:51
Show Gist options
  • Save nastanford/fa1ad6e8585d3ce63090e23deef15291 to your computer and use it in GitHub Desktop.
Save nastanford/fa1ad6e8585d3ce63090e23deef15291 to your computer and use it in GitHub Desktop.
JavaScript Drag & Drop
<h1>10 Richest People</h1>
<p>Drag and drop the items into their corresponding spots</p>
<ul class="draggable-list" id="draggable-list"></ul>
<button class="check-btn" id="check">
Check Order
<svg viewBox="0 0 24 24">
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</svg>
</button>
<!-- GitHub: https://github.com/saulgavrilov/js-drag-drop -->
const log = console.log;
const draggableList = document.getElementById('draggable-list');
const check = document.getElementById('check');
const richestPeople = [
'Jeff Bezos',
'Bill Gates',
'Warren Buffett',
'Bernard Arnault',
'Carlos Slim Helu',
'Amancio Ortega',
'Larry Ellison',
'Mark Zuckerberg',
'Michael Bloomberg',
'Larry Page',
];
// Store list items
const listItems = [];
// Keep track the index of each list item
let dragStartIndex;
createList();
// This function responsible to generate the list items
// "Insert list items into DOM"
function createList() {
[...richestPeople]
.map((a) => ({ value: a, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map((c) => c.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>
<svg viewBox="0 0 24 24">
<line x1="8" y1="6" x2="21" y2="6"></line>
<line x1="8" y1="12" x2="21" y2="12"></line>
<line x1="8" y1="18" x2="21" y2="18"></line>
<line x1="3" y1="6" x2="3.01" y2="6"></line>
<line x1="3" y1="12" x2="3.01" y2="12"></line>
<line x1="3" y1="18" x2="3.01" y2="18"></line>
</svg>
</div>
`;
listItems.push(listItem);
draggableList.appendChild(listItem);
});
addEventListeners();
}
function dragStart() {
// log('Event: ', 'dragStart');
dragStartIndex = +this.closest('li').getAttribute('data-index');
// log(dragStartIndex);
}
function dragOver(e) {
// log('Event: ', 'dragOver');
e.preventDefault();
}
function dragDrop() {
// log('Event: ', 'dragDrop');
const dragEndIndex = +this.getAttribute('data-index');
swapItems(dragStartIndex, dragEndIndex);
this.classList.remove('over');
}
// Swap list items that are drag and drop
function swapItems(from, to) {
const itemOne = listItems[from].querySelector('.draggable');
const itemTwo = listItems[to].querySelector('.draggable');
listItems[from].appendChild(itemTwo);
listItems[to].appendChild(itemOne);
}
function dragEnter() {
// log('Event: ', 'dragEnter');
this.classList.add('over');
}
function dragLeave() {
// log('Event: ', 'dragLeave');
this.classList.remove('over');
}
// Check the order of list items
function checkOrder() {
listItems.forEach((listItem, index) => {
const personName = listItem.querySelector('.draggable').innerText.trim();
if (personName !== richestPeople[index]) {
listItem.classList.add('wrong');
} else {
listItem.classList.add('right');
listItem.classList.remove('wrong');
}
});
}
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);
:root {
--main-color: #037fff;
--text-color: #34444f;
--bg-dark: #10121b;
--secondary-dark: #2e344e;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
height: 100vh;
font-family: sans-serif;
}
body > h1,
body > p {
padding: 0.8rem;
}
svg {
width: 24px;
height: 24px;
stroke: currentColor;
stroke-width: 2;
fill: none;
stroke-linecap: round;
stroke-linejoin: round;
}
.draggable-list {
border: 1px solid var(--secondary-dark);
color: var(--text-color);
list-style-type: none;
}
.draggable-list li {
background: #ffffff;
display: flex;
flex: 1;
}
.draggable-list li:not(:last-of-type) {
border-bottom: 1px solid var(--secondary-dark);
}
.draggable-list .number {
background: var(--bg-dark);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.2rem;
height: 60px;
width: 60px;
}
.draggable-list .person-name {
margin: 0 1rem 0 0;
}
.draggable-list li.right .person-name {
color: #3ae374;
}
.draggable-list li.wrong .person-name {
color: #ff3838;
}
.draggable-list li.over {
border-bottom: none;
}
.draggable-list li.over .draggable {
background: #c7c7c7;
}
.draggable {
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem;
flex: 1;
}
.check-btn {
background: var(--bg-dark);
color: #ffffff;
border: none;
outline: none;
padding: 0.8rem 1rem;
display: flex;
align-items: center;
justify-content: center;
margin-top: 1rem;
cursor: pointer;
}
.check-btn:active {
transform: scale(0.98);
}
.check-btn svg {
margin-left: 0.5rem;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment