Search code examples
javascriptreactjsreact-dnd

How to detect if draggable item is droppable at current location in react-dnd


I am looking for a way to detect if a draggable item is droppable at the current location.

For example, I want to print console.log('I can not be dropped here') every time the droppable item is being moved at a location which is not droppable.

Let's take the following pseudo mark up as an example:

<body>
  <h1>cool heading - you cant drop me here</1>
  <droptarget1>
    you can drop me here
  </droptarget1>
  <droptarget2>
    or you can drop me here
  </droptarget2>
  <dragsource>
    I can be dragged
  </dragsource>
</body>

When hovering dragsource over h1 I want the console to print 'I can not be dropped here'.

I was not able to find a solution in the docs and would appreciate any help.


Solution

  • React DND will detect a drop event being fired only if the element being dragged is dropped over a valid drop target (as in it's itemType must be included in the allowable drop targets), so you won't be able to do this right out of the box.

    What you can do however is set it so that each drop target that you want to know this state about is configured to have all of your itemTypes allowable and then handle whether they can or can't be dropped with another prop that you pass to the component yourself. Then within the drop function you can use this prop to determine whether to actually handle the drop or console log that it cannot be dropped. It might look something like this:

    import React, { PropTypes } from 'react';
    import { DropTarget } from 'react-dnd';
    
    import { ItemTypes } from 'myItemTypes';
    
    
    const myDropComponentTarget = {
      drop(props, monitor, component) {
        if ((monitor.getItemType() === ItemTypes.MY_ITEM_TYPE) && canDropMyItemType) {
          console.log('CAN DROP ITEM TYPE HERE')
        } else {
          console.log('CANNOT DROP ITEM TYPE HERE')
        }
      }
    }
    
    function collect(connect) {
      return {
        connectDropTarget: connect.dropTarget(),
      }
    }
    
    class MyDropComponent extends React.Component {
    
      static propTypes = {
        connecDropTarget: PropTypes.func.isRequired,
        canDropMyItemType: PropTypes.bool.isRequired,
      }
    
      render() {
        return this.props.connectDropTarget(
          <div>
            CHECK IF YOU CAN DROP HERE
          </div>
        );
      }
    }
    
    module.exports = DropTarget([ItemTypes.MY_ITEM_TYPE], myDropComponentTarget, collect)

    Note that you can even make drop containers around things that you don't want anything to actually be droppable in, and just always log that it can't be dropped, if you want that kind of interaction.