Search code examples
javascriptsortablejs

SortableJS - Drag element into sibling as a child


I'm new to using SortableJS, so I'm not sure if this is by design or if I'm doing it wrong.
I can drag elements to be children of elements that already have at least one child element, but I cannot drag them into elements that don't have any children. And if I drag all the elements out of an element so that it has none, I cannot drag them back into that element again.

Here's my code; I can drag anything to be a child of Home, PHP Support, or PHP 7 Support. Nothing else will accept a child element.

$(document).ready(function() {
  document.querySelectorAll("#category-list ul").forEach(function(listEl) {
    new Sortable(listEl, {
      group: "nested",
      handle: ".handle",
      animation: 150,
      fallbackOnBody: true,
      swapThreshold: 0.65,
      onEnd: function(evt) {
        var order = [];
        $("#category-list li").each(function(index, element) {
          order.push({
            id: $(element).data("id"),
            parent_id: $(element).closest("ul").closest("li").data("id") || null,
            position: index
          });
        });
      }
    });
  });
});
@import "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css";
@import "https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/fontawesome.min.css";
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/js/all.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.2/Sortable.min.js"></script>

    <div class="container" id="handle">
      <ul class="list-group" id="category-list">
        <li class="list-group-item" data-id="17"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Home<ul>
            <ul class="list-group" id="category-list">
              <li class="list-group-item" data-id="15"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Test Forum</li>
              <li class="list-group-item" data-id="9"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Hosting Support</li>
              <li class="list-group-item" data-id="21"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Forum</li>
              <li class="list-group-item" data-id="10"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP Support<ul>
                  <ul class="list-group" id="category-list">
                    <li class="list-group-item" data-id="18"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP 7 Support<ul>
                        <ul class="list-group" id="category-list">
                          <li class="list-group-item" data-id="20"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>HTAccess</li>
                        </ul>
                      </ul>
                    </li>
                    <li class="list-group-item" data-id="11"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP 8 Support</li>
                    <li class="list-group-item" data-id="19"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>MySQL Support</li>
                  </ul>
                </ul>
              </li>
            </ul>
          </ul>
        </li>
      </ul>
    </div>


Solution

  • I was able to solve the issue by adjusting my code a bit. This script ensures that all list items, even those without children, have a nested ul element initialized. This way, I can drag elements to any list item, regardless of whether it initially has children.

    function initializeSortable(el) {
            new Sortable(el, {
                group: 'nested',
                animation: 150,
                handle: ".handle",
                fallbackOnBody: true,
                swapThreshold: 0.65,
                onEnd: function (evt) {
                    var order = [];
                    $('#category-list li').each(function (index, element) {
                        order.push({
                            id: $(element).data('id'),
                            parent_id: $(element).closest('ul').closest('li').data('id') || null,
                            position: index
                        });
                    });
                }
            });
        }
    
        document.querySelectorAll('#category-list ul').forEach(function (listEl) {
            initializeSortable(listEl);
        });
    
        document.querySelectorAll('#category-list li').forEach(function (listItem) {
            if (!listItem.querySelector('ul')) {
                var newUl = document.createElement('ul');
                newUl.classList.add('list-group');
                listItem.appendChild(newUl);
                initializeSortable(newUl);
            }
        });
    @import "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css";
    @import "https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/fontawesome.min.css";
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/js/all.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.2/Sortable.min.js"></script>
    
    
    <ul class="list-group" id="category-list">
        <li class="list-group-item" data-id="17"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Home
            <ul class="list-group">
                <li class="list-group-item" data-id="15"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Test Forum</li>
                <li class="list-group-item" data-id="21"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Forum</li>
                <li class="list-group-item" data-id="10"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP Support
                    <ul class="list-group">
                        <li class="list-group-item" data-id="11"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP 8 Support</li>
                        <li class="list-group-item" data-id="18"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>PHP 7 Support
                            <ul class="list-group">
                                <li class="list-group-item" data-id="20"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>HTAccess</li>
                                <li class="list-group-item" data-id="19"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>MySQL Support</li>
                            </ul>
                        </li>
                    </ul>
                </li>
                <li class="list-group-item" data-id="9"><i class="fa-solid fa-up-down-left-right handle pe-2"></i>Hosting Support</li>
            </ul>
        </li>
    </ul>