1

I found this code, thats lets you drag and drop an item in an specific area, but I failed to rewrite it, so that it allowes multiple elments to drag and drop, because i dont know how to get the id of the dragged object from the drop_handler function.

let offsetX;
let offsetY;

onDragStart = function(ev) {
  const rect = ev.target.getBoundingClientRect();

  offsetX = ev.clientX - rect.x;
  offsetY = ev.clientY - rect.y;
};

drop_handler = function(ev) {
  ev.preventDefault();

  const left = parseInt(id2.style.left);
  const top = parseInt(id2.style.top);

  id1.style.position = 'absolute';
  id1.style.left = ev.clientX - left - offsetX + 'px';
  id1.style.top = ev.clientY - top - offsetY + 'px';
  id2.appendChild(document.getElementById("id1"));
};

dragover_handler = function(ev) {
  ev.preventDefault();
  ev.dataTransfer.dropEffect = "move";
};
<div id="id1" draggable="true" ondragstart="onDragStart(event)" style="border:2px solid green; cursor:pointer;width:100px;height:50px;">Dragged Div</div>


<div id="id2" style="position:absolute;left:200px;top:50px;border:2px solid red; cursor:pointer;width:200px;height:200px;" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Div
</div>

1
  • I see the problem! You can not have `...getElementById("id1") in drop_handler if you have more than one draggable box because id1 is hard coded. You need a variable which has the id of the box which was dragged... Not sure how to do that (yet). Commented Nov 24, 2022 at 15:47

2 Answers 2

1

In the onDragStart, 'save' the dragElement. This way you can use this variable in drop_handler to move the item.

I've added a const for the dropElement since this won't change.

let offsetX;
let offsetY;
let dragElement = null;
const dropElement = document.getElementById("id-drop");

onDragStart = function(ev) {
  const rect = ev.target.getBoundingClientRect();

  offsetX = ev.clientX - rect.x;
  offsetY = ev.clientY - rect.y;
  
  dragElement = ev.target;
};

drop_handler = function(ev) {
  ev.preventDefault();

  const left = parseInt(dropElement.style.left);
  const top = parseInt(dropElement.style.top);

  dragElement.style.position = 'absolute';
  dragElement.style.left = ev.clientX - left - offsetX + 'px';
  dragElement.style.top = ev.clientY - top - offsetY + 'px';
  dropElement.appendChild(dragElement);
};

dragover_handler = function(ev) {
  ev.preventDefault();
  ev.dataTransfer.dropEffect = "move";
};
<div id="id1" draggable="true" ondragstart="onDragStart(event)" style="border:2px solid green; cursor:pointer;width:100px;height:50px;">Dragged Div #1</div>

<div id="id2" draggable="true" ondragstart="onDragStart(event)" style="border:2px solid green; cursor:pointer;width:100px;height:50px;">Dragged Div #2</div>

<div id="id-drop" style="position:absolute;left:200px;top:50px;border:2px solid red; cursor:pointer;width:200px;height:200px;" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Div
</div>

Sign up to request clarification or add additional context in comments.

Comments

1

I have made a div just to keep track of the id of the draggable box. A data attribute is assigned the id from dragover_handler and then it can be read from drop_handler:

The other answer has a more sensible way of saving the id than this. There is no need to put it into an HTML element. If you are going to put the value into an HTML element it would be more sensible to use an appropriate existing element such as the target box than to create an unrelated element for the purpose.

let offsetX;
let offsetY;

const keepTrackOfID = document.querySelector('#keep-track-of-id');

onDragStart = function(ev) {
  const rect = ev.target.getBoundingClientRect();

  offsetX = ev.clientX - rect.x;
  offsetY = ev.clientY - rect.y;
  
  keepTrackOfID.setAttribute('data-dragged-id', ev.target.id);
  
};

drop_handler = function(ev) {
  ev.preventDefault();

  const left = parseInt(id2.style.left);
  const top = parseInt(id2.style.top);

  id1.style.position = 'absolute';
  id1.style.left = ev.clientX - left - offsetX + 'px';
  id1.style.top = ev.clientY - top - offsetY + 'px';
  id2.appendChild(document.getElementById(keepTrackOfID.dataset.draggedId));
  
  console.log(ev.target.id);
  
};

dragover_handler = function(ev) {
  ev.preventDefault();
  ev.dataTransfer.dropEffect = "move";
};
<div id="id1" draggable="true" ondragstart="onDragStart(event)" style="border:2px solid green; cursor:pointer;width:100px;height:50px;">Dragged Div 1</div>

<div id="id1b" draggable="true" ondragstart="onDragStart(event)" style="border:2px solid green; cursor:pointer;width:100px;height:50px;">Dragged Div 1b</div>

<div id='keep-track-of-id'></div>

<div id="id2" style="position:absolute;left:200px;top:50px;border:2px solid red; cursor:pointer;width:200px;height:200px;" ondrop="drop_handler(event)" ondragover="dragover_handler(event)">Drop Div
</div>

2 Comments

Why an extra div? You could add the data-dragged-id to the dropContainer since that will always be there?
@0stone0 I agree (also mentioned it now in my answer) there is no need for extra div. The dropContainer would have made a better choice. As far as I understand you have just declared a variable in the global (relative to the two functions) space to keep track of the id. That seems to make sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.