SortableJS / Sortable

Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
https://sortablejs.github.io/Sortable/
MIT License
29.78k stars 3.7k forks source link

Clone + Nesting : Allow only certain elements #2239

Closed Blackcode closed 1 year ago

Blackcode commented 1 year ago

It is possible to allow only certain elements to be nested inside others?

Example: Application element can contain only Container elements. Container only Queries, and Queries different types of Components.

CodePen Example

image

triumphhub commented 1 year ago

Hello Blackcode,

Sorry I'm late to the party. I solved this with classes and data-id. I hope this is helpful.

<html>
    <head>
      <meta charset="utf-8">
      <title>Sortable demo</title>
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
    </head>
    <body>
        <div id="nested1" class="container">
            <div id="nestedDemo" class="list-group col nested-sortable">
                <div data-sortable-id="list_group_1" class="mb-1  list-group-item nested-1 list_group" style="background-color:rgba(0,130,200,0.2);"><span id="list_group_1" style="font-size:130%;">Group 1</span>
                    <div class="list-group nested-sortable">
                        <div data-sortable-id="grp_1_list_1" class="mb-1 list-group-item nested-2 list">Group 1 list 1</div>
                        <div data-sortable-id="grp_1_list_2" class="mb-1 list-group-item nested-2 list">Group 1 list 2</div>
                        <div data-sortable-id="grp_1_list_3" class="mb-1 list-group-item nested-2 list">Group 1 list 3</div>
                        <div data-sortable-id="grp_1_list_4" class="mb-1 list-group-item nested-2 list">Group 1 list 4</div>
                    </div>
                </div>
                <div></div>
                <div data-sortable-id="list_group_2" class="mb-1 list-group-item nested-1 list_group" style="background-color:rgba(60,180,75,0.2)"><span id="list_group_2" style="font-size:130%;">Group 2</span>
                    <div class="list-group nested-sortable">
                        <div data-sortable-id="grp_2_list_5" class="mb-1 list-group-item nested-2 list">Group 2 list 5</div>
                        <div data-sortable-id="grp_2_list_6" class="mb-1 list-group-item nested-2 list">Group 2 list 6</div>
                        <div data-sortable-id="grp_2_list_7" class="mb-1 list-group-item nested-2 list">Group 2 list 7</div>
                        <div data-sortable-id="grp_2_list_8" class="mb-1 list-group-item nested-2 list">Group 2 list 8</div>
                    </div>
                </div>
                <div></div>
                <div data-sortable-id="list_9" class="mb-1 list-group-item nested-1 list">list 9</div>
                <div data-sortable-id="list_10" class="mb-1 list-group-item nested-1 list">list 10</div>
            </div>
            <div style="padding: 0" class="col-12">
            </div>
        </div>

        <script src="https://raw.githack.com/SortableJS/Sortable/master/Sortable.js"></script>

        <script>
            // Nested demo
            let nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
            var draggedDepth = 0;
            // Loop through each nested sortable element
            for (let i = 0; i < nestedSortables.length; i++) {
                new Sortable(nestedSortables[i], {
                    group: 'nested',
                    pull: function (to, from) {
                      console(from.el.children.length);
                    },
                    animation: 300,
                    fallbackOnBody: true,
                    swapThreshold: 0.65,
                    // Event when you move an item in the list or between lists
                    onMove: function (/**Event*/evt, /**Event*/originalEvent) {
                        /////Explore evt object
                        console.dir(evt.related);
                        ///// some useful stuff
                        console.dir(evt.related.offsetParent.classList.value);
                        console.dir(evt.dragged.dataset.sortableId);

                        ///// check if target parent class has list_group
                        const sentence = evt.related.offsetParent.classList.value;
                        const word = 'list_group';
                        result = sentence.includes(word);
                        ///// check if dragged parent class target has list_group
                        const sentence1 = evt.dragged.dataset.sortableId;
                        result1 = sentence1.includes(word);

                        //Refuse if criteria is wrong (eg. group cannot nest inside another group)
                        if(result == true){
                            if(result1 == true ){
                                return false;
                            }
                        }else{

                        }
                    },
                    ///// (php) Send new order to DB
                    onUpdate:function(evt){
                        var xhr = false;
                        xhr = new XMLHttpRequest();
                        if (xhr) {
                            xhr.onreadystatechange = function () {
                                if (xhr.readyState == 4 && xhr.status == 200) {
            //                        some stuff here
                                }
                            }
                            xhr.open("POST", "post.php", true);
                            xhr.send(JSON.stringify(serialize(root)));
                        }
                    },
                });
            }

            const nestedQuery = '.nested-sortable';
            const identifier = 'sortableId';
            const root = document.getElementById('nestedDemo');
            function serialize(sortable) {
                let serialized = [];
                let children = [].slice.call(sortable.children);
                for (let i in children) {
                    let nested = children[i].querySelector(nestedQuery);
                    serialized.push({
                        id: children[i].dataset[identifier],
                        children: nested ? serialize(nested) : []
                    });
                }
                return serialized
            }
            ///// Save original list if needed
            let reset_list = JSON.stringify(serialize(root));
            console.log(reset_list);
        </script>
    </body>
</html>
owen-m1 commented 1 year ago

Yes, the group option (https://github.com/SortableJS/Sortable#group-option) allows you to set a function for pull and put, which can be used to disallow items from certain groups. Please see the JSbin demos there.