P.S.
I figure you probably also want to work out when a component has changed position in python this is possible… but requires more leg work… I’ve had a play around and here’s some additional code that will make this happen:
https://anvil.works/build#clone:6IRFB67BBM6WJTS6=XFHHHJKQDMEG56OCJ7HBBC6U
The pseudo code is as follows:
- add the
anvil components
to theleft/right
slots as before - add the
anvil components
to ajavascript array
- use the
dragula
ondrop
event listener which provides theelement
,target
,source
andsibling
. - use the
javascript array
to get theanvil component
that was dropped, and thesibling component
- use
anvil.call
to send these back to python
Javascript in addition to the previous code
drake = dragula([document.querySelector('#left'), document.querySelector('#right')]);
drake.on('drop', function(element, target, source, sibling){
const anvil_component = get_component(element);
const anvil_sibling = get_component(sibling);
anvil.call(element, 'dropped', anvil_component, target.id, source.id, anvil_sibling);
});
var components = [];
function get_component(parent) {
if (parent === null){
return
}
for(i=0; i<components.length; i++){
if (components[i]._anvil.element[0] == parent.firstElementChild){
return components[i];
}
}
};
function add_component(component) {
components.push(component.v)
};
Python code
class DragulaForm(DragulaFormTemplate):
def __init__(self, **properties):
# Set Form properties and Data Bindings.
self.init_components(**properties)
# Any code you write here will run when the form opens.
self.left_components = []
self.right_components = []
self.slots = {'left': self.left_components, 'right': self.right_components}
# left components add dynamically
for i in range(10):
component = Button(text=f'button_{i}', role='raised')
self.left_components.append(component)
self.add_component(component, slot='left')
# right components add dynamically
for i in range(10, 20):
component = Button(text=f'button_{i}', role='raised')
self.right_components.append(component)
self.add_component(component, slot='right')
print(f"{'element':9} | {'from':5} | {'to':5} | {'at_index'}")
print("="*36)
def dropped(self, element, slot_to, slot_from, sibling):
self.slots[slot_from].remove(element)
for i, sib in enumerate(self.slots[slot_to]):
if sib is sibling:
break
else: # it was added after the last element so no sibling...
i+=1
self.slots[slot_to] = self.slots[slot_to][:i] + [element] + self.slots[slot_to][i:]
print(f"{element.text:9} | {slot_from:5} | {slot_to:5} | {i}")
def form_show(self, **event_args):
"""This method is called when the HTML panel is shown on the screen"""
from itertools import chain
for component in chain(self.left_components, self.right_components):
self.call_js('add_component', component)
managed to get itertools in there
In Action