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:开发者_如何学JAVA
$(".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!
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);
}
});
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();
});
This doesn't work for me, so I assume I'm doing something wrong. But I was wondering, if it works for you, why not set:
if ($(this).attr("id") == $(event.target).attr("id"))
To this:
if (this === event.target)
I'll update once I figure this out.
Still nothing: during that infinite loop, the event.target
remains as the slider, not the handle, only then is the second event actually triggered.
EDIT: Got it, I switched from jQuery 1.7.1 to 1.6.4 and it works.
精彩评论