Reputation: 1714
In the docs it says:
DragHandleProps
need to be applied to the node that you want to be the drag handle. This is a number of props that need to be applied to the<Draggable />
node. The simplest approach is to spread the props onto the draggable node ({...provided.dragHandleProps}
). However, you are also welcome to monkey patch these props if you also need to respond to them.DragHandleProps
will benull
whenisDragDisabled
is set to true.
dragHandleProps
Type information
type DragHandleProps = {|
// what draggable the handle belongs to
'data-rbd-drag-handle-draggable-id': DraggableId,
// What DragDropContext the drag handle is in
'data-rbd-drag-handle-context-id': ContextId,
// Id of hidden element that contains the lift instruction (nicer screen reader text)
'aria-labelledby': ElementId,
// Allow tabbing to this element
tabIndex: number,
// Stop html5 drag and drop
draggable: boolean,
onDragStart: (event: DragEvent) => void,
|};
I want to attach onDragStart
to the Draggable
so that it is fired only when a particular set of elements is dragged (as opposed to attaching it to DragDropContext
).
Using the example from the docs I do:
<Draggable draggableId="draggable-1" index={0}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
onDragStart={() => console.log('onDragStart')}
>
Drag me!
</div>
)}
</Draggable>
however it doesn't seem to be working. Any ideas how to make it work?
Upvotes: 7
Views: 10800
Reputation: 1683
If you want to achieve this kind of behavior, you can wrap the react-beautiful-dnd
context provider with your context provider, then use a hook to register the events you want in every component.
Context Provider - needs to wrap the app:
import React from 'react';
import {
DragDropContext
} from 'react-beautiful-dnd';
export const MyDragDropContext = React.createContext({});
export const DragAndDropContext = ({
children
}) => {
const [eventsMap] = React.useState(() => new Map());
const addEvent = (event, callback) => {
eventsMap.set(event, callback);
};
const emitEvent = (event, ...rest) => {
if (!eventsMap.has(event)) return;
eventsMap.get(event)(...rest);
};
const removeEvent = (event) => {
eventsMap.delete(event);
};
const handleDragEnd = (item) => {
if (!item.destination) return;
emitEvent(item.destination.droppableId, {
action: 'DRAG_END',
item
});
};
const handleDragStart = (item) => {
if (!item.source) return;
emitEvent(item.source.droppableId, {
action: 'DRAG_START',
item
});
};
return ( <
MyDragDropContext.Provider value = {{addEvent,removeEvent}} >
<DragDropContext
onDragStart = {handleDragStart}
onDragEnd = {handleDragEnd}
>
{children}
</DragDropContext>
</MyDragDropContext.Provider >
);
};
Hook:
import React, {
useRef
} from 'react';
import {
MyDragDropContext
} from './DragAndDropContext';
export interface DragMonitorListener {
onDragStart(item) : void;
onDragEnd(item) : void;
}
export default function useDragMonitor(droppableId, listener: DragMonitorListener) {
const {
addEvent,
removeEvent
} = React.useContext < any > (MyDragDropContext);
const savedListener = useRef < DragMonitorListener > ();
React.useEffect(() => {
savedListener.current = listener;
addEvent(droppableId, ({
action,
item
}) => {
if (action === 'DRAG_START') {
listener.onDragStart(item);
} else if (action === 'DRAG_END') {
listener.onDragEnd(item);
}
});
return () => removeEvent(droppableId);
}, []);
}
To get the callbacks in your component you need to register with the droppable id:
useDragMonitor('droppable-id', {
onDragStart(item) {
console.log('onDragStart', item);
},
onDragEnd(item) {
console.log('onDragEnd', item);
},
});
Upvotes: 0
Reputation: 605
onDragStart
and onDragEnd
are events for DragDropContext
component only.
Upvotes: 1
Reputation: 182
It can only be used only in DragDropContext for the Draggable element.
<DragDropContext
onDragStart={()=>{alert('onDragStart')}}
onDragEnd={()=>{alert('onDragEnd')}}>
</DragDropContext>
Upvotes: 6