max
max

Reputation: 380

Avoid nested groups with SortableJS

I need to do something like this example in SortableJs doc but in addition I also need Nested Sortables lists. This is not a problem, I've achived.

The wrong part is that I must implement a costraint in nested groups, because I need to avoid neasted groups. A group cannot be neasted inside another group. A single element can be neasted inside a group.

Let see an image, this is ok, we have two groups (item2 and item5) with some single elements inside

ok

But, this is forbidden for my project, a group inside a grop (item5 in item2)

error

I'd try to control things by the events: 'onChoose', 'onStart', 'onEnd', 'onAdd', 'onUpdate', 'onSort', 'onRemove', 'onChange', 'onUnchoose'. But without results.

Here is my code:

<div id="nested" class="row">
    <div id="example2-left" class="list-group nested-sortable col-sm-5">
        <div class="list-group-item">Item 1</div>
        <div class="list-group-item">Item 2
            <div class="list-group nested-sortable"></div>
        </div>
        <div class="list-group-item">Item 4</div>
        <div class="list-group-item">Item 3</div>
        <div class="list-group-item">Item 4</div>
        <div class="list-group-item">Item 5
            <div class="list-group nested-sortable"></div>
        </div>
        <div class="list-group-item">Item 6</div>
    </div>

    <div id="example2-right" class="list-group col-sm-5">
        <div class="list-group-item">Item 1</div>
        <div class="list-group-item">Item 2</div>
        <div class="list-group-item">Item 5</div>
        <div class="list-group-item">Item 3</div>
        <div class="list-group-item">Item 6</div>
    </div>
</div>

and the js

$(document).ready(function() {
var nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
for (var i = 0; i < nestedSortables.length; i++) {
    new Sortable(nestedSortables[i], {
        group: 'shared',
        animation: 150,
        fallbackOnBody: true,
        swapThreshold: 0.65,
        // trying to control elements
        onChange: function(e) {
            console.log('Left: onChange');
            console.log(e);
            e.preventDefault();
            return false;
        },
        onUnchoose: function(e) {
            console.log('Left: onUnchoose');
            console.log(e);
            e.preventDefault();
            return false;
        },
    });
}

new Sortable($('#example2-right')[0], {
    group: 'shared',
    animation: 150,
    onUnchoose: function(e) {
        console.log('Right: onUnchoose');
        console.log(e);
        e.preventDefault();
        return false;
    },
    onAdd: function(e) {
        console.log('Right: onAdd');
        console.log(e);
        e.preventDefault();
        return false;
    },
    onChange: function(e) {
            console.log('Right: onChange');
            console.log(e);
            e.preventDefault();
            return false;
        },
});
});

Upvotes: 3

Views: 1802

Answers (1)

user3058870
user3058870

Reputation: 83

Sorry I'm late to the party. This might help.

<!DOCTYPE html>
<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>





Upvotes: 0

Related Questions