To create a list of components in a Vaadin web app that have Drag & Drop functionality, you’ll need to integrate several items that will improve User Experience.
Drag & Drop Requirements And Events
To have this funcionality at all – you neet to instruct the browser
- What Elements are draggable
- What other Elements are drop – possible
This is part of the HTML W3C Standard https://html.spec.whatwg.org/multipage/dnd.html#the-draggable-attribute, so every modern browser should have these APIs.
dragstart
Indicates that a dragging operation has started. This event usually sets some data in a buffer and changes the cursor icon to – if the current position of the mouse/fingure is drop allowed.
dragend
The user has finished the dragging operation. This means – mouse has been released /or fingure lifted/. If the current location of the mouse wasn’t a drop allowed – nothing changes.
dragenter
Indicates that the mouse/fingure has entered an area where it is possible to drop.
dragleave
Indicates that the mouse/fingure has left an area where it is possible to drop.
drop
The user has finished dragging – and – on location where it is allowed to drop.
Vaadin Snippets
Vaadin has several utilities that ease integrating drag and drop functionality.
DragSource
The first way to make component draggable is by implementing DragSource interface
class MyComponent extends Component implements DragSource<MyComponent>
and call:
setDraggable(true);
setDragData(data);
The other way that could be executed on any component – is through static method:
DragSource.create(component);
DropTarget
The same goes for Drop Target:
Make any component possible drop location.
DropTarget<Div> target = DropTarget.create(div);
Or, implement DropTarget<MyComponent> and call:
dropTarget.setActive(active);
On the drop target – you could have additional semantic – what will change the cursor icon (DropEffect):
- COPY,
- MOVE,
- LINK,
- NONE;
You implement all logic and UI changes you want – by attaching these events.
dragTarget.getElement().addEventListener("dragenter", domEvent -> {});
dragTarget.getElement().addEventListener("dragleave", domEvent -> {});
target.addDropListener(divDropEvent -> { Optional<Object> dragData = divDropEvent.getDragData(); /*Do something with this*/ });
You could check out a demonstration of this code in the video https://www.youtube.com/watch?v=BgGTRkkbgEA.
The code will be part of https://programtom.com/dev/product/mission-accomplished-spring-boot-vaadin-web-app/.
Edit for Mobile
All the above code works for Desktop users – with a mouse. On Mobile – when you tap on the screen – other types of events are fired:
- touchstart
- touchcancel
- touchleave
- touchmove
- touchend
You could attach all of these to start and end items:
dragTarget / dropTarget.getElement() .addEventListener(“touchstart|…“, domEvent -> {});
1. DragEnter: `touchstart`
This is because the `dragenter` event is triggered when a dragging operation begins over an element, which can be simulated by the user starting to touch the screen at that location.
2. DragLeave: `touchmove` or `touchcancel`
The `dragleave` event is triggered when a dragging operation ends outside an element, which can happen if the user touches and drags their finger outside of the element’s bounds, resulting in a `touchmove` event. Alternatively, if the touch gesture is cancelled (e.g., due to a new touch or a scroll), it could trigger a `touchcancel` event.
3. Drop: `touchend`
This event is triggered when the user drops an item over an element, which happens at the end of a touch event (`touchend`).
4. DragStart: `touchstart` with `dataTransfer` property set
While `touchstart` can trigger a drag operation, setting the `dataTransfer` property on the `touchstart` event is not possible in the same way as with mouse events (e.g., `dragstart`). However, if you need to simulate a drag-and-drop behavior, you could use a library or framework like Hammer.js that supports touch-based drag-and-drop interactions.
5. DragEnd: `touchend`
Similar to `drop`, this event is triggered when the user stops touching an element after initiating a dragging operation.
My Version of Mobile DND
While you could archive similar functionality with these events, they require a lot of polishing to get them right – especially for smaller screens – where the normal scrolling is actually “drag and drop” gesture – on non-event space. Intead – I’ve implemented it with the following steps:
- Added an icon that activates move operation on tap (without holding your fingure). If you implement drag-start on the full item – the normal scrolling will become user un-friendly.
You could scroll up or down – with visible drop locations (without touching on them). They need to be big enough for a fingure. The drop locations also need to indicate what will happen when tapped.
- Tap on the drop location.
This way – in a work-around approach – drag and drop is possible through list of 20 items, even when the screen could display – up to 3 items.