stimulus-sortable
                                
                                 stimulus-sortable copied to clipboard
                                
                                    stimulus-sortable copied to clipboard
                            
                            
                            
                        Stimulus-sortable as a nested sortable not working
Hi @michaelbaudino ! Can you tell me if this component works as a nested? If so, how to use it as a nested?
Hi @ducho, I'm not sure why you mentioned me since I'm not a maintainer of this project, but I'd recommend asking @guillaumebriday :smirk:
The issue seems to be that the nested sortable controller is receiving a disconnect message from Stimulus.
To fix this locally I modified my code to have the parent sortable apply a class to the body when the drag starts and remove it when the drag completes. I actually need that for a different aspect of my user interface. I was able to use this "state" in the disconnect logic of the nested sort.
  disconnect() {
    // If we are dragging any item around, ignore the disconnect message
    // and leave the state of this sortable along. However, if no drag
    // is happening, we will process the disconnect request
    if (!document.body.classList.contains('active-dragging')) {
      super.disconnect()
    }
  }
I suspect there might be another state that could be tested to prevent this. I also suspect that it has something to do with an interaction between SortableJS cloning/moving logic and a MutationObserver in Stimulus that is attempting to do some automatic clean up.
So for me this was a huge pain, especially in a nested Sortable.
Thanks @gstark for pointing me in the right direction! I ended up with a way more convoluted logic, especially since you can't just use the onStart and onEnd SortableJS methods as onStart is called too late.
I ended up extending my SortableJS Stimulus controller like this:
export default class extends Sortable {
	bodyClass = 'sortablejs-sorting'
	awaitingConnect = false
	awaitingDisconnect = false
	listenerOpts = {
		capture: true,
		passive: true,
	}
	downListener = (e) => {
		document.body.classList.add(this.bodyClass)
	}
	upListener = (e) => {
		document.body.classList.remove(this.bodyClass)
		this.handleWaiting()
	}
	handleWaiting = () => {
		if (this.awaitingDisconnect) {
			this.awaitingDisconnect = false
			this.disconnect()
		}
		if (this.awaitingConnect) {
			this.awaitingConnect = false
			this.connect()
		}
	}
	connect() {
		// Stimulus listens to DOM change events and calls connect() and disconnect() automatically
		// this unfortunately breaks SortableJS, so we need to (attempt to) prevent this behavior.
		// This behavior also needs to be global to apply to other sortables that might be in the same group,
		// so we use a body class to share the state.
		if (this.options.supportPointer){
			this.element.addEventListener('pointerdown', this.downListener, this.listenerOpts)
			this.element.addEventListener('pointerup', this.upListener, this.listenerOpts)
		} else {
			this.element.addEventListener('mousedown', this.downListener, this.listenerOpts)
			this.element.addEventListener('mouseup', this.upListener, this.listenerOpts)
			this.element.addEventListener('touchstart', this.downListener, this.listenerOpts)
			this.element.addEventListener('touchend', this.upListener, this.listenerOpts)
		}
		if (!document.body.classList.contains(this.bodyClass)) {
			super.connect()
		} else {
			this.awaitingConnect = true
		}
	}
	disconnect() {
		if (this.options.supportPointer){
			this.element.removeEventListener('pointerdown', this.downListener, this.listenerOpts)
			this.element.removeEventListener('pointerup', this.upListener, this.listenerOpts)
		} else {
			this.element.removeEventListener('mousedown', this.downListener, this.listenerOpts)
			this.element.removeEventListener('mouseup', this.upListener, this.listenerOpts)
			this.element.removeEventListener('touchstart', this.downListener, this.listenerOpts)
			this.element.removeEventListener('touchend', this.upListener, this.listenerOpts)
		}
		if (!document.body.classList.contains(this.bodyClass)) {
			super.disconnect()
		} else {
			this.awaitingDisconnect = true
		}
	}
	get defaultOptions() {
		return {
			onEnd: this.upListener.bind(this),
		}
	}
	// .....
}
This seems to be a fully-working workaround, but I'd suggest that anyone who considers using Stimulus-Sortable and wants to use groups for moving items between lists reconsiders. It's a pain.
And I don't really fault the authors either; I'm not even sure what the proper fix is. The way Stimulus works seems to be kinda incompatible with SortableJS architecture (which, on its own, also makes sense).