Only the last draggable <div> element / JS function stops when released and not the previous?

Issue

I am having problems with the following code (heavily cut down version). essentially I am trying to make the two different windows draggable (via the title bar only). It works perfectly when there is only one window, however, once I add another – they’re both draggable, but one (first called in the code) won’t let go.

makeDragable('#handle_1', '#moveable_1')
makeDragable('#handle_2', '#moveable_2')

So ‘#handle_1’, ‘#moveable_1’ would not be dropped after releasing the mouse.

This is my first time using JS – and html/css properly so I am sorry if this is a fundamental error. The JS is not my code. I am assuming the problem lies here:

/* End dragging */
document.onmouseup = function(e) {
    if (dragObj) {
        dragObj = null;

But just can’t work it out. I’d prefer to use this code as it allows me to only allow the main bar to be draggable rather than the entire window. I apologise if my post is convoluted, any critique would be highly appreciated as this is my first Stack post.

Thanks in advance!

body {
  background-image: url('https://www.betaarchive.com/imageupload/1304990899.or.90622.png');
  font-family: "Pixelated MS Sans Serif",Arial;
  font-size: 11px;
}

.grid-container {
  display: grid;
  gap: 10px;
  font-size: 13px;
  margin: 15px 35px 35px 35px;
}

.grid-container > div {
  text-align: center;
  margin: 10px 0px 10px 0px;
}
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="https://unpkg.com/xp.css"/>
        <link rel="stylesheet" href="styles_login.css"/>
        <title>Login Screen</title>
    </head>
    <body>
        <div id="moveable_1">
            <div class="window" style="width: 350px; position: absolute; left: 100px; top: 150px;">
                <div id="handle_1" class="title-bar">
                    <div class="title-bar-text">Login Screen</div>
                </div>
                <div class="window-content">
                    <div class="window-content-inner"></div>
                    <div class="status-bar">
                        <p class="status-bar-field">Test</p>
                    </div>
                </div>
            </div>
        </div>
        <div id="moveable_2">
            <div class="window" style="width: 650px; position: absolute; left: 450px; top: 300px;">
                <div id="handle_2" class="title-bar">
                    <div class="title-bar-text">Chat Screen</div>
                </div>
                <div class="window-content">
                    <div class="window-content-inner"></div>
                    <div class="status-bar">
                        <p class="status-bar-field">Test 2</p>
                    </div>
                </div>
            </div>
        </div>
    </body>
    <script src="./renderer.js"></script>

    <script> // Draggable Content JS
        function makeDragable(dragHandle, dragTarget) {
        let dragObj = null; //object to be moved
        let xOffset = 0; //used to prevent dragged object jumping to mouse location
        let yOffset = 0;

        document.querySelector(dragHandle).addEventListener("mousedown", startDrag, true);
        document.querySelector(dragHandle).addEventListener("touchstart", startDrag, true);

        /*sets offset parameters and starts listening for mouse-move*/
        function startDrag(e) {
            e.preventDefault();
            e.stopPropagation();
            dragObj = document.querySelector(dragTarget);
            dragObj.style.position = "absolute";
            let rect = dragObj.getBoundingClientRect();

            if (e.type=="mousedown") {
            xOffset = e.clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
            yOffset = e.clientY - rect.top;
            window.addEventListener('mousemove', dragObject, true);
            } else if(e.type=="touchstart") {
            xOffset = e.targetTouches[0].clientX - rect.left;
            yOffset = e.targetTouches[0].clientY - rect.top;
            window.addEventListener('touchmove', dragObject, true);
            }
        }

        /*Drag object*/
        function dragObject(e) {
            e.preventDefault();
            e.stopPropagation();

            if(dragObj == null) {
            return; // if there is no object being dragged then do nothing
            } else if(e.type=="mousemove") {
            dragObj.style.left = e.clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
            dragObj.style.top = e.clientY-yOffset +"px";
            } else if(e.type=="touchmove") {
            dragObj.style.left = e.targetTouches[0].clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
            dragObj.style.top = e.targetTouches[0].clientY-yOffset +"px";
            }
        }

        /*End dragging*/
        document.onmouseup = function(e) {
            if (dragObj) {
            dragObj = null;
            window.removeEventListener('mousemove', dragObject, true);
            window.removeEventListener('touchmove', dragObject, true);
            }
        }
        }

        makeDragable('#handle_1', '#moveable_1')
        makeDragable('#handle_2', '#moveable_2')
    </script>
</html>

Link to original code

Solution

Your problem was that you were storing a dragObj for each "window" inside the function call (captured via a closure). Hence when you switched to the other one, it all went a bit wrong. Moving the
let dragObj = null; line outside of your MakeDraggable function makes it work correctly.

You would be better developing a draggable/window class that encapsulates each window. You could then store a static variable that holds the dragObj there (rather than making it wholly global, as we have it now.

Let me know if you need any further help.

body {
  background-image: url('https://www.betaarchive.com/imageupload/1304990899.or.90622.png');
  font-family: "Pixelated MS Sans Serif",Arial;
  font-size: 11px;
}

.grid-container {
  display: grid;
  gap: 10px;
  font-size: 13px;
  margin: 15px 35px 35px 35px;
}

.grid-container > div {
  text-align: center;
  margin: 10px 0px 10px 0px;
}
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="https://unpkg.com/xp.css"/>
        <link rel="stylesheet" href="styles_login.css"/>
        <title>Login Screen</title>
    </head>
    <body>
        <div id="moveable_1">
            <div class="window" style="width: 350px; position: absolute; left: 100px; top: 150px;">
                <div id="handle_1" class="title-bar">
                    <div class="title-bar-text">Login Screen</div>
                </div>
                <div class="window-content">
                    <div class="window-content-inner"></div>
                    <div class="status-bar">
                        <p class="status-bar-field">Test</p>
                    </div>
                </div>
            </div>
        </div>
        <div id="moveable_2">
            <div class="window" style="width: 650px; position: absolute; left: 450px; top: 300px;">
                <div id="handle_2" class="title-bar">
                    <div class="title-bar-text">Chat Screen</div>
                </div>
                <div class="window-content">
                    <div class="window-content-inner"></div>
                    <div class="status-bar">
                        <p class="status-bar-field">Test 2</p>
                    </div>
                </div>
            </div>
        </div>
    </body>
    <script src="./renderer.js"></script>

    <script> // Draggable Content JS
        let dragObj = null; //object to be moved
        function makeDraggable(dragHandle, dragTarget) {
        let xOffset = 0; //used to prevent dragged object jumping to mouse location
        let yOffset = 0;

        document.querySelector(dragHandle).addEventListener("mousedown", startDrag, true);
        document.querySelector(dragHandle).addEventListener("touchstart", startDrag, true);

        /*sets offset parameters and starts listening for mouse-move*/
        function startDrag(e) {
            e.preventDefault();
            e.stopPropagation();
            dragObj = document.querySelector(dragTarget);
            dragObj.style.position = "absolute";
            let rect = dragObj.getBoundingClientRect();

            if (e.type=="mousedown") {
            xOffset = e.clientX - rect.left; //clientX and getBoundingClientRect() both use viewable area adjusted when scrolling aka 'viewport'
            yOffset = e.clientY - rect.top;
            window.addEventListener('mousemove', dragObject, true);
            } else if(e.type=="touchstart") {
            xOffset = e.targetTouches[0].clientX - rect.left;
            yOffset = e.targetTouches[0].clientY - rect.top;
            window.addEventListener('touchmove', dragObject, true);
            }
        }

        /*Drag object*/
        function dragObject(e) {
            e.preventDefault();
            e.stopPropagation();

            if(dragObj == null) {
            return; // if there is no object being dragged then do nothing
            } else if(e.type=="mousemove") {
            dragObj.style.left = e.clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
            dragObj.style.top = e.clientY-yOffset +"px";
            } else if(e.type=="touchmove") {
            dragObj.style.left = e.targetTouches[0].clientX-xOffset +"px"; // adjust location of dragged object so doesn't jump to mouse position
            dragObj.style.top = e.targetTouches[0].clientY-yOffset +"px";
            }
        }

        /*End dragging*/
        document.onmouseup = function(e) {
            if (dragObj) {
            dragObj = null;
            window.removeEventListener('mousemove', dragObject, true);
            window.removeEventListener('touchmove', dragObject, true);
            }
        }
        }

        makeDraggable('#handle_1', '#moveable_1')
        makeDraggable('#handle_2', '#moveable_2')
    </script>
</html>

Answered By – Lee Taylor

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published