react-draggable
react-draggable copied to clipboard
How to prevent execution of "click" event after drag?
Hi,
I have Draggable element and inside of it, I have a component with onClick event. At the end of the drag, the click event is triggered. My question is how to prevent this action and how to seperate these to event?
Thanks.
There's not any way that I'm aware of to stop the event from reaching the child. I assume you want a click to keep working, but a drag to prevent the click from happening. You can accomplish this with some local state.
https://codesandbox.io/s/nervous-burnell-e2r95?file=/src/App.js
Same problem
Hi guys, you may take a look at this example https://codesandbox.io/s/material-demo-gc0le?file=/demo.js from https://stackoverflow.com/questions/59136239/how-handle-long-press-event-in-react-web.
You may consider drag as a 'long press'. So you can distinguish between a click event and a drag event by checking their pressing time.
Just need to return the onClick event if a long press is detected.
onClick={(e) => { e.stopPropagation() if (isCommandHandled) return //some actions here }}
Hi guys,
I just had a simular problem, and the way I solved it was by checking if a drag happened by checking the deltaX and Y. If not drag happened, then I call the "onClick" handler. Maybe this could be incorporated in the source code? I would gladly send a PR
I use this, to handle the drag only after a time lapse
const PRESS_TIME_UNTIL_DRAG_MS = 250:
const IconDraggable = ({ children, onClick }) => {
const [isDragging, setDragging] = useState(false)
const handleClick = () => {
if (isDragging === true) {
return
}
onClick()
}
return (
<Draggable
onStart={() => setTimeout(() => setDragging(true) , PRESS_TIME_UNTIL_DRAG_MS)}
onDrag={e => {
if (isDragging === false) {
e.preventDefault()
return false
}
}}
>
<div style={{ position: 'absolute' }} onClick={() => handleClick(isDragging)}>
{children}
</div>
</Draggable>
)
}
Hi guys,
I just had a simular problem, and the way I solved it was by checking if a drag happened by checking the deltaX and Y. If not drag happened, then I call the "onClick" handler. Maybe this could be incorporated in the source code? I would gladly send a PR
I've tried all the solutions above and this seems like the best solution, where less accurate clicks that drag for a few pixels are still counted as clicks. The below code shows the logic implemented.
`
const [dragStartPos, setDragStartPos] = useState({ x: 0, y: 0 });
const onStart = (e) => {
setDragStartPos({ x: e.screenX, y: e.screenY });
};
const onStop = (e) => {
const dragX = Math.abs(dragStartPos.x - e.screenX);
const dragY = Math.abs(dragStartPos.y - e.screenY);
if (dragX < 5 || dragY < 5) {
console.log(`click with drag of ${dragX}, ${dragY}`);
// onClick functionality here
} else {
console.log(`click cancelled with drag of ${dragX}, ${dragY}`);
}
};
`
Using a ref to store the "isDragged" state works well for me.
const Parent: React.FC<Props> = () => {
const draggedRef = useRef<boolean>(false)
return (
<Draggable
handle=".handle"
onDrag={() => {
draggedRef.current = true
}}
>
<div className="handle">
<Child draggedRef={draggedRef}/>
</div>
</Draggable>
)
}
const Child: React.FC<Props> = ({
draggedRef,
}: {
draggedRef: React.MutableRefObject<boolean>
}) => {
function onClick() {
const dragged = draggedRef.current
draggedRef.current = false
if (!dragged) {
alert('button was clicked but not dragged')
}
}
return <button onClick={onClick}>A Button</button>
}
add this css to your child wrapper comp.
for example
<Draggable ...>
<ChildCompWrapper isDragging={isDragging}>
{...............}
</ChildCompWrapper>
</Draggable>
const ChildCompWrapper = styled.divpointer-events: ${({ isDragging }) => isDragging && 'none'};
Using a ref to store the "isDragged" state works well for me.
const Parent: React.FC<Props> = () => { const draggedRef = useRef<boolean>(false) return ( <Draggable handle=".handle" onDrag={() => { draggedRef.current = true }} > <div className="handle"> <Child draggedRef={draggedRef}/> </div> </Draggable> ) } const Child: React.FC<Props> = ({ draggedRef, }: { draggedRef: React.MutableRefObject<boolean> }) => { function onClick() { const dragged = draggedRef.current draggedRef.current = false if (!dragged) { alert('button was clicked but not dragged') } } return <button onClick={onClick}>A Button</button> }
Thanks It Worked!!!