Sortable
Sortable copied to clipboard
Keep initial position of item
Similar to Chrome or Firefox Bookmarks Toolbar. It keeps initial position of item during dragging, showing a line at the position when item is potentially dropped.
Hey, also interested in a solution for this. I have the part when you transform the chosenClass: "sortable-chosen" and transform the element to a bar:
:host(.sortable-chosen) {
visibility: hidden;
height: 1px;
position: relative;
&::before {
content: '';
visibility: visible;
border-bottom: 1px solid $primary;
width: 100%;
height: 0;
position: absolute;
top: 0;
left: 0;
}
}
But I can't achieve to let the item at its initial position and do the move only on dragEnd...
Thanks in advance for anyone helping on this!
I achieve something which is quite hacky but seems to work so far. I create a clone of my element and reinsert it in the DOM at the same place of the dragged element. And remove it onDragEnd. I have some issue of DOM rendering but it's because I use webcomponent. For normal DOM element this should work perfectly:
import Sortable from 'sortablejs';
import { EventEmitter } from '@stencil/core';
export function initMenuSort(el: HTMLElement, emitter: EventEmitter) {
let persistentClone: HTMLElement = null;
const sort = Sortable.create(el, {
draggable: '.my-draggable',
handle: '.drag-handle',
filter: 'my-menu-action',
group: { name: 'menu' },
ghostClass: 'sortable-ghost',
chosenClass: 'my-sortable-chosen',
sort: true,
onStart: (e: any) => {
const el = e.item as HTMLMyComponentElement;
let index = e.oldIndex;
if (index < 0) {
index = 0;
}
// @TODO el.cloneNode(true) (deep=true)
// this cause the component to rerender and display the content <slot> twice
// when stenciljs will be bulletproof on cloneNode(deep=true) we will have the clone properly displaying
persistentClone = e.from.insertBefore(
el.cloneNode(),
e.from.children[index]
);
persistentClone.classList.add('my-sortable-disable');
persistentClone.classList.remove('my-draggable');
console.log(persistentClone);
console.log(e);
el.dragStart();
},
onEnd: (e: any) => {
const data = {
oldIndex: e.oldIndex,
newIndex: e.newIndex,
item: e.item,
newParent: e.to,
oldParent: e.from
};
const el = e.item as HTMLMyComponentElement;
el.dragEnd();
persistentClone.remove();
persistentClone = null;
emitter.emit(data);
},
onMove: e => {
// If it's not draggable, we cancel the move
if (e.related.classList.contains('my-draggable')) {
return true;
}
return false;
}
});
return sort;
}
Adapte the code to your case ;)
Perhaps a placeholder element option, to stay in the original position of the element?
We are having issues when sorting an item and then re-rendering a stencil component, this causes sortable to repeat the previous drag action - I am not sure why this is occurring. @Nightbr is this the issue you were trying to get around ?
Hey @miguelyoobic95 it's another problem you describe. But we manage to include sortableJS with stenciljs component, we use our fork -> "sortablejs": "https://github.com/saloonio/Sortable.git#dev-firefoxShadowRoot"
We use a stenciljs component container which instantiate sortablejs:
componentDidLoad() {
this.sortableElement = Sortable.create(this.el.querySelector('.components') as HTMLElement, {
handle: '.drag-icon',
draggable: '.plop-draggable',
filter: 'plop-new-component-container soon-button',
animation: 150,
onStart: e => {
const el = e.item as HTMLPlopComponentElement;
el.dragStart();
},
onEnd: e => {
const el = e.item as HTMLPlopComponentElement;
el.dragEnd();
this.drop(e);
},
onMove: e => {
// If it's not draggable, we cancel the move
if (e.related.classList.contains('plop-draggable')) {
return true;
}
return false;
}
});
}
I'm also interested in this feature. Another great example for this is Notion:
This would be a great idea for a plugin. I could try to make it myself, but if anyone else wants to give it a try - the docs for creating a plugin are here: https://github.com/SortableJS/Sortable/blob/master/plugins/README.md
using our code snippet https://github.com/SortableJS/Sortable/issues/1345#issuecomment-434630156 & https://github.com/SortableJS/Sortable/issues/1345#issuecomment-434655435
@Nightbr Would you be interested in making your implementation into a plugin?
I don't think it could be easy because I'm wrapping SortableJS into a Stenciljs webcomponent. But I could try if I have spare time ;)
Is there any plugin or API available to achieve this using just SortableJS?
I am also stuck with the same problem.
Is there any plugin or API available to achieve this using just SortableJS?
+1 We need this :D
This would be a great idea for a plugin. I could try to make it myself, but if anyone else wants to give it a try - the docs for creating a plugin are here: https://github.com/SortableJS/Sortable/blob/master/plugins/README.md
Are there still any plans for this?
Just leaving a +1. This is the same functionality we would like to achieve. Thanks!
+1
+1
+1
+1
+1
+1
Any new?
This would be a great idea for a plugin. I could try to make it myself, but if anyone else wants to give it a try - the docs for creating a plugin are here: https://github.com/SortableJS/Sortable/blob/master/plugins/README.md
Any news?
+1
+1
+1
+1
@songispm @Klapik @kotoyama @9brada6 @miroshnichenkoYaroslav @semivori @joaobarcia
This can implemented without a plugin using @Nightbr's method. Here's a more minimal version:
Keep an original copy in place as you drag:
onStart(e) {
// Add a clone in the original location
const persistentClone = e.from.insertBefore(
e.item.cloneNode(true),
e.from.children[e.oldIndex as number]
) as HTMLElement
// give it a class so we can remove it later
persistentClone.classList.add('sortable-clone')
// remove irrelevant classes
persistentClone.classList.remove('sortable-chosen', 'sortable-ghost')
},
onEnd(e){
// remove persisted clones
e.from.querySelectorAll('.sortable-clone').forEach(child => child.remove())
}
.sortable-ghost ends up being the blue line you want - but you'll need to do some styling to hide is contents, make it blue, etc.
My elements are table rows so I had to do some css trickery to get the line to work consistently between rows:
tbody {
// ensure the absolutely positioned table row stays contained within the tbody
position: relative;
}
// Position the table row line and hide its contents
.sortable-ghost {
// eliminate goofy layout shifting
position: absolute;
// make it full width
display: block;
width: 100%;
// Overly robust hack to hide text contents within the line element
text-indent: -9999px;
font-size: 0.001px;
line-height: 0;
color: transparent;
}
// Create the actual line
.sortable-ghost::before{
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
height: 3px;
background: blue;
}
Use Swap plugin:
https://sortablejs.github.io/Sortable/#swap https://github.com/SortableJS/Sortable/tree/master/plugins/Swap
Use Swap plugin:
https://sortablejs.github.io/Sortable/#swap https://github.com/SortableJS/Sortable/tree/master/plugins/Swap
No, the Swap plugin swaps the dragged element with the destination element. Totally different feature.