Sortable
Sortable copied to clipboard
Nested sortable max level.
How do I find it? "deep , maxDeep"
"pull": function(event) { if(deep > maxDeep) return false; return true; },
You'll have to define your own functions to figure this out. The question is out of scope, but happy to keep it open for a while so others can answer.
Very late to comment, but take a look at this comment: https://github.com/SortableJS/Sortable/issues/1979#issuecomment-757687788
So if you take a look at the source code for nested lists: https://github.com/SortableJS/Sortable/blob/0656d6245f222c4dc26cd08777d7bd04b7699c29/index.html#L312-L318
we can classify list items as those that do not have div children and "folders" as those that have children, specifically a div with class "list-group". Disclaimer, this is just my specific use case if you're familiar with that interface there; otherwise, the only other way I can describe the following is like a "filesystem". Using the aforementioned comments code, set every "list-group-item" to have an attribute "data-level" to specify depth, then:
onMove(ev) {
const lvl = parseInt(ev.related.getAttribute("data-level"));
if (ev.dragged.querySelector(".list-group") && lvl >= 2)
return false;
const diff = parseInt(ev.dragged.getAttribute("data-level")) - lvl;
ev.dragged.setAttribute("data-level", lvl);
for (let x of ev.dragged.querySelectorAll(".list-group-item")) {
x.setAttribute("data-level",
parseInt(x.getAttribute("data-level")) - diff
)
}
}
where that last for loop is for constantly updating the level. return false
will prevent the item from dropping. 3 is the depth. It's up to you to make up whatever conditions and initial levels are given.
For my specific use case, I only allowed one nested folder. If the level start from 0
, then I could have one folder inside another folder but that was it. That second folder could still contain items though. To accomplish this, the if statement should have an AND
i.e. && that asks ev.dragged.querySelector(".list-group")
basically checking if the currently dragged item is a folder.
@Andrew-Chen-Wang
I also needed to limit to a depth of 1 nested folder.
i started with your code, but ended up with this, i think it achieves the same. I used JQuery to turn event.to
in a JQuery object.
It counts the number of parents with the nested-sortable
class:
onMove(event) {
const lvl = $(event.to).parents('.nested-sortable').length;
if (lvl > 1)
{
return false;
}
}
Hope this helps someone else.
if use in project JQuery code @VincentVanWijk work. but if i don't use jquery, how get current lvl for item?
I spent some time searching internet and nothing worked, so I made my own version which works:
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.2/Sortable.min.js"></script>
</head>
<body>
<div id="nestedDemo" class="list-group col nested-sortable">
<div class="list-group-item is-folder">Folder 1
<div class="list-group nested-sortable folder">
<div class="list-group-item">File 1</div>
<div class="list-group-item">File 2</div>
<div class="list-group-item">File 3</div>
</div>
</div>
<div class="list-group-item is-folder">Folder 2
<div class="list-group nested-sortable folder"></div>
</div>
<div class="list-group-item is-folder">File 4</div>
<div class="list-group-item is-folder">Folder 3
<div class="list-group nested-sortable folder">
<div class="list-group-item">File 5</div>
</div>
</div>
<div class="list-group-item">File 6</div>
</div>
<script>
// Loop through each nested sortable element
nestedSortables = document.getElementsByClassName('nested-sortable');
for (var i = 0; i < nestedSortables.length; i++) {
new Sortable(nestedSortables[i], {
group: 'nested',
animation: 150,
fallbackOnBody: true,
swapThreshold: 0.65,
onMove(ev) {
var into_folder = ev.to.classList.contains('folder');
var is_folder = ev.dragged.classList.contains('is-folder');
if (into_folder && is_folder)
return false;
return true;
}
});
}
</script>
<style>
.list-group-item {
margin: 0 0 0 10px;
}
</style>
</body>
</html>