Pablo Darde
Pablo Darde

Reputation: 6402

How to implement a simple native Drag and Drop?

I'm trying to implement a simple drag and drop effect on a div. I'm using the native HTML5 API. Basically, I'm trying to drag the left pink box to the dark gray area. See the fiddle: All seems to be ok, however, I'm not able to drop the box in the dark gray area.

https://jsfiddle.net/pablodarde/2wy1s2vn/

I'm using this documentation as support.

This is my code:

HTML

<div class="container">
  <div class="side-bar">
    <div class="box" draggable='true'></div>
  </div>
  <div class="drop-zone"></div>
</div>

JavaScript

const box = document.querySelector('.box');
const dropZone = document.querySelector('.drop-zone');

const handleDragStart = (e) => {
    console.log(e.dataTransfer);
  e.dataTransfer.effectAllowed = 'move';
};

const handleDragEnter = (e) => {
    e.target.className += ' active-drop';
  e.dataTransfer.dropEffect = 'move';
  console.log(e.dataTransfer);
  e.preventDefault();
  e.stopPropagation();
}

const handleDragLeave = (e) => {
  e.target.className = 'drop-zone';
}

const handleDrop = (e) => {
    console.log('Drop!!');
  e.preventDefault();
  e.stopPropagation();
}

box.addEventListener('dragstart', handleDragStart);

box.addEventListener('drop', handleDrop);

dropZone.addEventListener('dragenter', handleDragEnter);

dropZone.addEventListener('dragleave', handleDragLeave);

Upvotes: 1

Views: 443

Answers (2)

Pablo Darde
Pablo Darde

Reputation: 6402

Although I accepted the above answer, I'm leaving here an option with React. I found out how to explore React state feature to easily build a simple drag and drop solution

Codepen https://codepen.io/pablodarde/pen/gGoQYo

JavaScript

class Square extends React.Component {
  constructor() {
    super();
    this.state = {
      posx: 10,
      posy: 10,
    };
    this.setDrag = this.setDrag.bind(this);
    this.startDrag = this.startDrag.bind(this);
    this.stopDrag = this.stopDrag.bind(this);
  }

  componentDidMount() {
    this.sq.addEventListener('mousedown', this.setDrag);
  }

  startDrag(e) {
    console.log('posx: ', this.state.posx);
    console.log('startPosX: ', this.startPosX);
    this.setState({
      posx: parseInt(e.clientX - this.startPosX, 10),
      posy: parseInt(e.clientY - this.startPosY, 10),
    });
    this.startPosX = e.clientX - this.state.posx;
    this.startPosY = e.clientY - this.state.posy;
  }

  stopDrag() {
    document.documentElement.removeEventListener('mousemove', this.startDrag);
    document.documentElement.removeEventListener('mouseup', this.stopDrag);
    this.sq.addEventListener('mousedown', this.setDrag);
  }

  setDrag(e) {
    console.log('mouse down');
    this.sq.removeEventListener('mousedown', this.setDrag);
    this.startPosX = e.clientX - this.state.posx;
    this.startPosY = e.clientY - this.state.posy;
    document.documentElement.addEventListener('mousemove', this.startDrag);
    document.documentElement.addEventListener('mouseup', this.stopDrag);
  }

  render() {
    return (
      <div
        className='square'
        style={{
          left: this.state.posx,
          top: this.state.posy,
        }}
        ref={(sq) => { this.sq = sq; }}
      >
        {this.state.posx}
      </div>
    );
  }
}

ReactDOM.render(
  <Square />,
  document.getElementById('app')
);

CSS

.square {
  position: absolute;
  width: 100px;
  height: 100px;
  background: #900;
  border: 1px solid #333;
}

Upvotes: 0

Rutwick Gangurde
Rutwick Gangurde

Reputation: 4912

The following 4 things should solve your browser/event related issues and handle the drop for you:

  1. The drop event has to be attached to the dropZone div.
  2. Cancel the event in the dragover event handler. You don't have one, add it.

For Firefox:

  1. Add the following line to your dragstart handler:

    e.dataTransfer.setData('sourceId', '<id of the source>');
    

This could be any key-value, but it has to be set for drag drop to work in Firefox. I have set the ID of the box since I want to use it in the drop handler.

  1. Drop handled to append the box to the dropzone: https://jsfiddle.net/kyqr1o6b/3/

Final working code with the drop handled: https://jsfiddle.net/kyqr1o6b/6/

Update: Added support for Firefox.

Update 2: Drop handled.

Update 3: Positions captured.

Upvotes: 1

Related Questions