Hi
After doing some sniffing around I got it working (thx to anyone who contributed):
The callback returns dragdrop info such as : element dragged, source/target container ids and their ordered children.
I kept within the scope of a mre but this method can easily be upgraded to support more dragula info if needed.
Python
import dash
from dash import dcc
import dash_bootstrap_components as dbc
from dash_extensions.enrich import DashProxy, html, Input, Output, State, ClientsideFunction, NoOutputTransform
import json
from pprint import pprint
app = DashProxy(transforms=[NoOutputTransform()])
app.config.external_stylesheets = ["https://epsi95.github.io/dash-draggable-css-scipt/dragula.css", dbc.themes.BOOTSTRAP]
app.config.external_scripts = ["https://cdnjs.cloudflare.com/ajax/libs/dragula/3.7.2/dragula.min.js",
"https://epsi95.github.io/dash-draggable-css-scipt/script.js"]
rows = ['aaa','bbb','ccc','ddd','eee','fff']
app.layout = dbc.Container(
[
html.Div([
dbc.Input(type='text', id='client_event_receiver', placeholder='', style={'visibility': 'hidden'}),
dbc.Row([
dbc.Col([
html.Div([
html.Div([
html.P(
x,
style={
'text-indent':'28px'
}
)
],
id = x,
style={
'backgroundColor':'rgb(180,180,180)',
'border': '1px solid black',
'height':'28px'
}
)
for x in rows
],
id="drag_container1",
className="container",
style ={
'backgroundColor' : 'rgb(100,100,100)',
'margin': 0,
'padding': 0,
'height' : '300px',
'overflow-y':'auto',
}
),
]),
dbc.Col([
html.Div(
[],
id="drag_container2",
className="container",
style ={
'backgroundColor' : 'rgb(100,100,100)',
'margin': 0,
'padding': 0,
'height' : '300px',
'overflow-y':'auto',
}
)
]),
]
)],
id="drag_container",
className="container",
style ={
'width':'80%'
}
),
],
className="dbc",
fluid=True,
)
app.clientside_callback(
ClientsideFunction(namespace="clientside", function_name="make_draggable_mre"),
Output("drag_container", "data-drag"),
[Input("drag_container1", "id"),Input("drag_container2", "id")
]
)
@app.callback(Input('client_event_receiver', 'value'))
def get_dragdrop_info(json_str):
if json_str:
value = json.loads(json_str)
print('-'*100)
pprint(value)
if __name__ == "__main__":
app.run_server(debug=True)
assets/script.js
if (!window.dash_clientside) {
window.dash_clientside = {};
var __rendezvouz_setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
}
window.dash_clientside.clientside = {
make_draggable_mre: function () {
let args = Array.from(arguments);
var containers = [];
setTimeout(function () {
for (i = 0; i < args.length; i++) {
containers[i] = document.getElementById(args[i]);
}
dragul = dragula(containers);
dragul.on("drop", function (el, target, source, sibling) {
var result = {
'element': el.id,
'target_id': target.id,
'target_children': Array.from(target.children).map(function (child) {return child.id;})
}
if (source.id != target.id) {
result['source_id'] = source.id;
result['source_children'] = Array.from(source.children).map(function (child) {return child.id;});
}
var client_event_receiver = document.getElementById("client_event_receiver");
__rendezvouz_setter.call(client_event_receiver, JSON.stringify(result));
var client_event = new Event('input', { bubbles: true });
client_event_receiver.dispatchEvent(client_event);
})
}, 1)
return window.dash_clientside.no_update
}
}
Prints the following when dragging the rows around:

Note that only the targets are returned when reordering inside the same container
As a base, I used:
var __rendezvouz_setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
to trigger events on a dummy dbc.Input object.
Guess it has something to do with React?
Although I can’t foresee many drawbacks to this method yet, I don’t have the necessary expertise to determine if this is good practice or not. I do not completely understand what I did, so if anyone can clarify, It would be nice receive some further explanations.
For as far as I know, dash-extensions doesn’t provide a way to return a callback from js. (please, correct me if I’m wrong)
I encountered quite a few questions similar to this one.
It would be nice if dash-extensions would implement something similar to the above for communicating client events to the server… in that that lovely, clean, streamlined fashion. Big up to the dash-extensions devs! ![]()