JsCoder
JsCoder

Reputation: 1733

set draggable in mousedown handler

Perhaps it's by design, but I want the handle to be draggable rightaway, not after the first mouseup as it currently happens.

<html>
<head>

    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/themes/base/minified/jquery-ui.min.css" rel="stylesheet" />

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.1/jquery-ui.min.js"></script>
    <script>
        $(function () {


            var handle = $("#handle");

            handle.on("mousedown", function () {

                // doesn't work
                handle.draggable();
            });


            // works
            handle.draggable();
        });
    </script>
</head>
<body>
    <div style="width: 400px; height: 400px; border: 2px solid gray; position: relative;">

        <div id="handle" style="width: 50px; height: 50px; position: absolute; top: 100px; left: 100px; background-color: gray;"></div>
    </div>
</body>
</html>

Upvotes: 2

Views: 1677

Answers (3)

mikeypie
mikeypie

Reputation: 149

You can fire your own mousedown event within the native event. This will continue the mousedown for jQuery draggable. This solution is conceptually similar to the one by Roberto Barra, but firing events has changed since that answer was posted.

const draggableEl = $('#dragEl');
draggableEl.draggable({
  helper: 'clone',
  revert: 'invalid',
  opacity: 0.5,
  disabled: true, //init with drag disabled for demo
});
console.log($('#dragEl').draggable('option'));

let initialized = false;
$(document).on('mousedown.myDragScope', function(e) {
  if ($(e.target).is($('#dragEl'))) {
    if (initialized) {
      //do any draggable stuff
      $(e.target).css('outline', '2px solid black'); //demo
      $(e.target).css('background', 'darkseagreen'); //demo
    } else {
      //initialize draggable
      e.preventDefault(); //pause mousedown event (to allow setting jQuery draggable options)

      //change jQuery draggable settings:
      $(e.target).draggable('option', 'disabled', false); //enable draggable after click on el for demo
      $(e.target).draggable('option', 'axis', 'x'); //demo
      // $(e.target).draggable('option', '...', '...');

      console.log($('#dragEl').draggable('option'));
      initialized = true;

      const mousedownEvent = new MouseEvent('mousedown', {
        view: window,
        cancelable: true,
        bubbles: true
      });
      e.target.dispatchEvent(mousedownEvent); //resume mousedown event to continue drag
    }
  }
});
#dragEl {
  width: fit-content;
  outline: 2px dotted black;
  background: thistle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js"></script>

<h2>dynamic setting of options on mousedown draggable element</h2>

<div id="dragEl">drag this el</div>

<p>this element has draggable disabled by default</p>
<p>mousedown on the element sets draggable enabled, sets some other draggable options, and then passes another mousedown event to the event for jQuery draggable to grab</p>
<p>mouseup is not handled by this demo, so the draggable remains enabled</p>

Upvotes: 0

Roberto Barra
Roberto Barra

Reputation: 25

I have the same need: to setup an element as draggable inside an event listener attached to the event mousedown of this same element. Andthe dragging must start with this mousedown event, I can't ask the user to click twice to be able to drag something!

Why do I need that?

Because when the user drags a box around, this box will drag together some ohter boxes, and I only have infromation of which boxes to drag together when the user clicks on one box.

This is how I did it:

  • adds a mousedown listener to the boxes.
  • on this listener: 1) checks if a drag already started. 2) If not: a) find out which boxes to drag together, b) make the box draggable, c) mark that the dragging already started and then d) creates a new mousedown event and dispatch it.

Below is a snippet of my code that do what I describe (and it is working, at least on Chrome...):

$.fn.adjustDragging = function (opts)
{
    // bDragNeed2BeAdjusted: if true, indicates that the box isn't draggable yet
    this[0].bDragNeed2BeAdjusted = true;
    this.mousedown(function(e)
    {
        if (this.bDragNeed2BeAdjusted)
        {
            this.bDragNeed2BeAdjusted = false;

            // Make box and her sisters draggable
            $(this).doAdjustDragging(opts);

            e.preventDefault();

            // Send a new mousedown event
            if (document.createEvent)
            {
                var evtNew = document.createEvent('MouseEvents');
                evtNew.initMouseEvent(
                    'mousedown', 
                    e.bubbles, e.cancelable, e.view, e.button, 
                    e.screenX, e.screenY, e.clientX, e.clientY, 
                    e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, this
                );
                this.dispatchEvent(evtNew);
            }
            else
            {
                options.clientX = options.pointerX;
                options.clientY = options.pointerY;
                var evtNew = document.createEventObject();
                evtNew = extend(evt, {clientX: e.pointerX, clientY: e.pointerY});
                this.fireEvent('onmousedown', evtNew);
            }

            return false;
        }
    });

};

Upvotes: 0

SirDerpington
SirDerpington

Reputation: 11470

I'm not really sure what you're trying to accomplish but your example demonstrates the correct behaviour.

If you init the .draggable() in the mousedown event it just means that the handle div gets initialized to be draggable when you first click on the div. After that it gets initalized again and again. So on page load your div doesn't know it has to be draggable. If you then click on it your mousedown event triggers and sets the div to be draggable.

If you want it to be draggable rightaway just use your second - working - example. It's perfectly fine or am I missing something? See this jsfiddle

The Default Functionality example in the jQuery UI documentation shows exactly this.

 $(function() {
    //element with ID "draggable" is draggable after the DOM has loaded
    $( "#draggable" ).draggable();
});

There's simply no need to wrap the .draggable() in a mousedown event.

Upvotes: 1

Related Questions