I am rewriting a jquery dragable script to plain javascript. At the insertBefore
(https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore) point I get this error message:
NotFoundError: Node.insertBefore: Child to insert before is not a child of this node.
This error occurs when I want to move a lower list element to the top.
Here is my code.
let items = document.querySelectorAll("#items-list > li");
items.forEach((item) => {
item.setAttribute("draggable", true);
item.addEventListener("dragstart", dragStart);
item.addEventListener("drop", dropped);
item.addEventListener("dragenter", cancelDefault);
item.addEventListener("dragover", cancelDefault);
});
const getNodeIndex = elm => [...elm.parentNode.children].indexOf(elm)
function dragStart(e) {
const index = getNodeIndex(e.target);
e.dataTransfer.setData("text/plain", index);
}
function dropped(e) {
cancelDefault(e);
// get new and old index
let oldIndex = e.dataTransfer.getData("text/plain");
let target = e.target;
let newIndex = getNodeIndex(e.target);
let droppedElement = e.currentTarget.parentNode.children[oldIndex];
droppedElement.remove();
// insert the dropped items at new place
if (newIndex < oldIndex) {
//---> this is the problematic line <---
target.insertBefore(droppedElement, e.currentTarget.parentNode);
} else {
target.after(droppedElement);
}
}
function cancelDefault(e) {
e.preventDefault();
e.stopPropagation();
return false;
}
<div class="container">
<ul id="items-list" class="moveable">
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>
</div>
2
Answers
You need to insert the dragged node into the
target.parentNode
, and before thetarget
:Example:
Another option is to use
Element.before()
in the same way you useElement.after()
:You are saying to append the li after the UL. The correct way would be
e.currentTarget.parentNode.insertBefore(droppedElement, target);
But you are using the old way, just use before.