Closed helixaros closed 1 year ago
Hello @1cg, I do have a question about having 2 SortableJS shared list that are grouped. When I dragged an item to other shared list, I want to trigger the form submission where the item has been dragged. Currently, I'm experiencing it only trigger the form submission where the item removed/moved on parent/belongs list. Is there any way that I could achieve those goals. Thank you very much!
@each(section in sections)
<form
hx-post="{{ route('workspaces.tasks.position', { id: workspace.id, sectionId: section.id }) }}"
hx-trigger="end"
hx-target="#section-{{ section.id }}"
hx-swap="outerHTML"
>
{{ csrfField() }}
<ul id="section-{{ section.id }}" class='sortable sections'>
@each(task in section.tasks)
<li>
<div>
<input type="hidden" name="taskIds" value="{{ task.id }}">
{{ task.priority }}
</div>
<div>
{{ task.title }} - {{ task.position }}
</div>
<div>
{{ task.createdAt.toFormat('LLL dd yyyy') }}
</div>
</li>
@end
</ul>
</form>
@end
javascript
import Sortable from 'sortablejs';
import htmx from 'htmx.org';
htmx.onLoad(function () {
const workspaceTasks = document.querySelectorAll('.sortable');
for (var i = 0; i < workspaceTasks.length; i++) {
let sortable = workspaceTasks[i];
new Sortable(sortable, {
group: 'sections',
filter: '.task-option',
animation: 150,
});
htmx.process(sortable);
}
});
I did some clever workaround by calling an ajax call with onEnd method of SortableJS, but it still has bug like if the hx-trigger="end"
resolve first and the SortableJS onMethod ajax call resolve last. It will return some issue like you can see the dragged item from the previous list. I'm still trying to figure out if there's better way to resolve this kind issue.
import Sortable from 'sortablejs';
// htmx is already on window
htmx.onLoad(function () {
const workspaceTasks = document.querySelectorAll('.sortable');
for (var i = 0; i < workspaceTasks.length; i++) {
let sortable = workspaceTasks[i];
new Sortable(sortable, {
group: 'sections',
filter: '.task-option',
animation: 150,
onEnd: (evt) => {
if (evt.pullMode) {
const toElement = evt.to;
const childrens = Array.from(toElement.children);
const ids = childrens.map(
(child) => child.querySelector('input').value
);
const formElement = toElement.closest('form');
const csrfToken = formElement
.querySelector("input[name='_csrf']")
.attributes.getNamedItem('value').value;
const htmxPath = formElement.attributes
.getNamedItem('hx-post')
.value.replace('position', 'drag');
const htmxTarget =
formElement.attributes.getNamedItem('hx-target').value;
const htmxSwap = formElement.attributes.getNamedItem('hx-swap').value;
const htmxValues = { taskIds: ids };
htmx.ajax('POST', htmxPath, {
target: htmxTarget,
swap: htmxSwap,
values: htmxValues,
headers: {
'x-csrf-token': csrfToken,
},
});
}
},
});
htmx.process(sortable);
}
});
Already solved it! What I did was call ajax on onEnd method of SortableJS if the event params from onEnd is evt.pullMode you can put your logic on how you're going to transfer the item into other list and persist on your backend and fetch the updated items and attach it on your partials html.
I hope it helps :)
Sample:
import Sortable from 'sortablejs';
// htmx is already on window
htmx.onLoad(function () {
const workspaceTasks = document.querySelectorAll('.sortable');
for (var i = 0; i < workspaceTasks.length; i++) {
let sortable = workspaceTasks[i];
new Sortable(sortable, {
group: 'sections',
filter: '.task-option',
animation: 150,
onEnd: (evt) => {
if (evt.pullMode) {
// Dragged item to other list
// ... your logic
htmx.ajax('POST', `/dashboard/workspaces/${workspaceId}/drag`, {
target: '#section-list',
swap: 'outerHTML',
values: {
sections: JSON.stringify({
[toElementId]: toIds,
[fromElementId]: fromIds,
}),
},
headers: {
'x-csrf-token': csrfToken,
},
});
return true;
}
// Changing the item position
// .... your logic
htmx.ajax(
'POST',
`/dashboard/workspaces/${workspaceId}/sections/${workspaceSectionId}/position`,
{
target: '#section-list',
swap: 'outerHTML',
values: {
taskIds: toElementIds,
},
headers: {
'x-csrf-token': csrfToken,
},
}
);
},
});
htmx.process(sortable);
}
});
I would catch the
end
event on each sortable w/ some scripting and trigger an event specific to that list that you could listen for w/hx-trigger.Easiest solution I can think of.