Drag and drop a dynamic array with Vue 3 — the easy way
Drag and drop a dynamic array with Vue 3 — the easy way
Drag and drop can be a daunting task, but I’ve created a foolproof step-by-step guide to make it easy to manage! With just a simple Javascript array and a few methods, you can have a powerful way to manage your items quickly and easily.
If you’re simply looking to peruse the code and witness a demonstration, check out the Codepen!
We can reach our desired outcome through the use of events. Before this, we’ll have to build an array as well as the HTML that it fits into. To do this, we’ll need to make an array of objects, with each object containing a slug and a label.
The array
const container = ref(null)
const items = ref([
{
slug: "item-1",
label: "Item 1"
},
{
slug: "item-2",
label: "Item 2"
},
{
slug: "item-3",
label: "Item 3"
},
{
slug: "item-4",
label: "Item 4"
}
])j
HTML
<div ref="container">
<template v-for="(item, idx) in items">
<div
class="item"
:data-slug="item.slug"
draggable="true"
v-text="item.label"
/>
</template>
</div>
Items swap
We now require a function to interchange two elements. This function will take the indices of the items with slug1 and slug2 and change their positions in the items array.
const swapItems = (slug1, slug2) => {
const indexFirstItem = items.value.findIndex(item => item.slug === slug1)
const indexSecondItem = items.value.findIndex(item => item.slug === slug2)
const temp = items.value[indexFirstItem]
items.value[indexFirstItem] = items.value[indexSecondItem]
items.value[indexSecondItem] = temp
}
Start dragging the element
At the beginning of the drag, we should store the slug of the dragged element in the event by using e.DataTransfer.setData.
const dragStart = (e) => {
const slug = e.target.dataset.slug
e.dataTransfer.setData('text/plain', slug)
}
Swapping elements on drop
When we put an item down, we want to exchange it with the item that we are dropping it on. To do this, we take the slug from the dataTransfer and then loop through to locate the slug of the element where we are placing it. Finally, we swap the two items by using their slugs.
const drop = (e) => {
e.preventDefault()
e.stopPropagation()
const slugOfFirstElement = e.dataTransfer.getData('text/plain')
const secondHtmlElement = e.target
// loop over second element to find the slug (for example the target could be an svg)
// we allow to search the data-slug on at most 10 parents
let i=0;
while(secondHtmlElement.dataset.slug === undefined && i < 10) {
secondHtmlElement = e.target.parentNode
i++
}
const slugSecondElement = secondHtmlElement.dataset.slug
swapItems(slugOfFirstElement, slugSecondElement)
}
Little fix
If we use the event dragstart, we need to handle the dragover event, otherwise no drop event will be triggered. To prevent this, we use the preventDefault function of the event.
const dragOver = (e) => {
e.preventDefault();
}
Adding event listeners
Finally, we need to put in events for our container. It’s better to attach the listeners to the container element instead of the individual items, because this way we only need one listener instead of multiple for each event type. Plus, with this approach, we can add and take away items without needing to add and remove listeners each time.
onMounted(() => {
container.value.addEventListener('dragstart', dragStart)
container.value.addEventListener('drop', drop);
container.value.addEventListener('dragover',dragOver)
})
✅ Congratulations! You have successfully created a dynamic drag and drop feature! If you found this to be useful, please consider sharing it on your social media platforms.