Reputation: 1954
I have tried to build a react app that has drag and drop list functionality without downloading any external packages. I found a tutorial that purports to do exactly that
This is my code:
class App extends React.Component {
state = {
items: ["3", "2", "1", "4"]
};
onDragStart = (e, index) => {
console.log("drag start!!!");
this.draggedItem = this.state.items[index];
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/html", e.target.parentNode);
e.dataTransfer.setDragImage(e.target.parentNode, 20, 20);
};
onDragOver = index => {
const draggedOverItem = this.state.items[index];
// if the item is dragged over itself, ignore
if (this.draggedItem === draggedOverItem) {
return;
}
// filter out the currently dragged item
let items = this.state.items.filter(item => item !== this.draggedItem);
// add the dragged item after the dragged over item
items.splice(index, 0, this.draggedItem);
this.setState({ items });
};
onDragEnd = () => {
this.draggedIdx = null;
};
render() {
return (
<div className="App">
<main>
<h3>List of items</h3>
<ul>
{this.state.items.map((item, idx) => (
<li key={item} onDragOver={() => this.onDragOver(idx)}>
<div
className="drag"
draggable
onDragStart={e => this.onDragStart(e, idx)}
onDragEnd={this.onDragEnd}
style={{ cursor: "pointer" }}
/>
<span className="content" style={{ cursor: "pointer" }}>
{item}
</span>
</li>
))}
</ul>
</main>
</div>
);
}
}
I don't get any bugs in console. However, the items in the list refuse to be dragged. On the offhand chance that I can drag an item, I can't get it to where I want to go and it introduces a weird gap/space:
This is my codesandbox:https://codesandbox.io/s/angry-dewdney-xzhsi
Upvotes: 1
Views: 1938
Reputation: 355
Add the "draggable=true" to the element to want to drag You need to allow dropping by adding this code to the element to want to drop on. HTML by default doesn't allow drops
onDragOver={event=>event.preventDefault()}
Upvotes: 0
Reputation: 295
Try changing the render to have the draggable div wrap the span with the text like this:
<div
className="drag"
draggable
onDragStart={e => this.onDragStart(e, idx)}
onDragEnd={this.onDragEnd}
style={{ cursor: "pointer" }}
>
<span className="content" style={{ cursor: "pointer" }}>
{item}
</span>
</div>
Otherwise you have to click on the empty div which would be next to impossible as you noted. This way the draggable div wraps the text so whenever you click on the text you're clicking the div.
Upvotes: 2