Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger draggable behaviour programmatically

I've created a "2d slider" in jQuery in which 2 parameters are manipulated simultaneously by dragging a "handle" within a bounding box.

I've implemented this by nesting a "handle" div within a parent div, and using the jQuery UI plugin to facilitate the dragging behaviour. The html looks like:

<div class="Slider2d" id="grid_spacing_both">
    <div class="Slider2dHandle" id="grid_spacing_both_handle"></div>
</div>

The jQuery looks like:

$(".Slider2dHandle").draggable({
    containment: "parent",
    scroll: false,
    drag: function(event, ui) {
        // calculates position and updates value input boxes
    }
});

I've also created some code that repositions the handle to the location of any clicks within the parent div:

$(".Slider2d").mousedown(function(event){
    // get location of click and reposition handle to click location
});

What I would like to do is modify the above method so that the user can click somewhere in the parent div, have the handle repositioned to the click location, and then begin dragging the handle without letting the mouse button up. Basically, I need to figure out a way to programmatically trigger the drag functionality.

I found a few suggestions here and here, and attempted to implement their recommendations by changing the above method like so:

$(".Slider2d").mousedown(function(event){
    // get location of click and reposition handle to click location
    handle = $(".Slider2d").children(".Slider2dHandle");
    handle.trigger(event);
});

This works in the most technical sense, but its super slow and I get a bunch of error messages from Safari telling me "RangeError: Maximum call stack size exceeded." What I'm thinking is happening is that the when I trigger the event on the handle, it bubbles up to the parent, which then calls the trigger again and so on and so on. I've tried to stop the bubbling by throwing an event.stopPropagation into my code before and after the .trigger() call, but to no avail.

So, if anyone has any suggestions on how to get this working I'd really appreciate it. I have a backup plan here, but this seems to me to be unnecessarily complicated.

Thanks!

like image 317
jkjenner Avatar asked Mar 09 '11 21:03

jkjenner


2 Answers

I managed to get this working. As I suspected, it had something to do with event handling.

The fix was simple: I modified the above code to check if the event target was the same as the element to which the callback was bound (ie, slider bounding box). On the initial click that repositions the handle, these are the same elements. However, when the handle's mousedown event is triggered, and the event bubbles up to the bounding box, the target of that event is the slider handle. So, they don't match, and the trigger event isn't called again, setting off an infinite loop.

At least I think that's what's going on. In any case, here's the code that worked:

$(".Slider2d").mousedown(function(event){
    // get location of click and reposition handle to click location 

    handle = $(".Slider2d").children(".Slider2dHandle");
    if ($(this).attr("id") == $(event.target).attr("id")) {
        handle.trigger(event);
    }
});
like image 117
jkjenner Avatar answered Nov 15 '22 09:11

jkjenner


Or you could just stop propagation at the handler's mousedown event so it doesn't bubble up to the slider's mousedown event.

$(".Slider2d").mousedown(function(event) {
    // get location of click and reposition handle to click location 

    handle = $(".Slider2d").children(".Slider2dHandle");
    handle.trigger(event);
});

$(".Slider2dHandle").mousedown(function(event) {
    event.stopPropagation();
});
like image 43
Twisted Whisper Avatar answered Nov 15 '22 09:11

Twisted Whisper