jQuery Drag And Drop Using Live Events
Solution 1
Wojtek's solution worked perfectly for me. I wound up changing it a tad bit to make it extend jQuery...
(function ($) {
$.fn.liveDraggable = function (opts) {
this.live("mouseover", function() {
if (!$(this).data("init")) {
$(this).data("init", true).draggable(opts);
}
});
return this;
};
}(jQuery));
Now instead of calling it like:
$(selector).draggable({opts});
...just use:
$(selector).liveDraggable({opts})
Solution 2
This is a sample of code that perfectly worked for me
$('.gadgets-column').live('mouseover',function(){
$(this).draggable();
});
Solution 3
You could make wrapper function like this:
function liveDraggable(selector, options){
jQuery(selector).live("mouseover",function(){
if (!jQuery(this).data("init")) {
jQuery(this).data("init", true);
jQuery(this).draggable(options);
}
});
}
(I use prototype with jQuery - that's why i placed jQuery() instead of $())
And now instead of $(selector).draggable({opts}) use liveDraggable(selector, {opts})
Solution 4
Stldoug's code worked for me, but there's no need to keep checking the element's .data("init") on every mouseover event. Also, it's better to use "mousemove", as "mouseover" doesn't always get triggered if your mouse is already over the element when the .live function kicks in.
(function ($) {
$.fn.liveDraggable = function (opts) {
this.live("mousemove", function() {
$(this).draggable(opts);
});
};
}(jQuery));
Here's how you use it:
$('.thing:not(.ui-draggable)').liveDraggable();
The trick is to add ":not(.ui-draggable)" to your selector. Since jQuery will automatically add the "ui-draggable" class to your element when it becomes draggable, the .live function will no longer target it. In other words, it only triggers once, unlike the other solution which triggers over and over as you move stuff around.
Ideally, you could just .unbind the "mousemove", but that doesn't work with .live, unfortunately.
Solution 5
Combining the best answers from @john and @jasimmk:
Using .live
:
$('li:not(.ui-draggable)').live('mouseover',function(){
$(this).draggable(); // Only called once per li
});
.live
is deprecated though, better to use .on
:
$('ul').on('mouseover', 'li:not(.ui-draggable)', function(){
$(this).draggable(); // Only called once per li
});
As @john explained, .ui-draggable
is automatically added to draggable methods, so by excluding that class with the selector, you ensure that draggable() will only be called once on each element. And using .on
will reduce the scope of the selector, improving performance.
Fred
All around JavaScripter. Blogger at badassjs.com. Audio hacker audiocogs.org. Engineer at Storify.
Updated on July 09, 2022Comments
-
Fred almost 2 years
I have an application with a long list that changes frequently, and I need the items of that list to be draggable.
I've been using the jQuery UI draggable plugin, but it is slow to add to 400+ list items, and has to be re-added every time new list items are added.
Does anyone know of a plugin similar to the jQuery UI draggable plugin that uses jQuery 1.3's
.live()
events? This would solve both problems. -
satyavrat over 13 yearsThis broke my js altogether. Do you need to put this somewhere in particular to extend the JQuery functionality?
-
stldoug about 13 yearsYou need to declare it after you load jQuery and before you use it in your code. What error are you getting?
-
stldoug almost 13 yearsYes, definitely cleaner. What do you think about moving the check for "ui-draggable" inside the plug-in function... something like "if(!this.hasClass('ui-draggable')){...}"?
-
Randomblue over 12 yearsYou forgot to return the element for chaining
-
Michal B. about 12 yearsit's an easy solution, but draggable is executed on all DOM elements with gadgets-column class everytime you hover one of them...
-
Morg. about 12 years@MichalB. No that is not how jQuery works, the $(this) refers to the item being mouseover'd and this can be even much lighter than having draggable() set before (i.e. the draggable logic will not be active until you mouseover).
-
Michal B. about 12 years@Morg: I agree with all you said, you just did not understand what I meant. Every time you hover an element that has class
gadgets-column
the code will execute. The code is$(this).draggable();
and that is not something you would like to execute every time you hover. -
Morg. about 12 yearsby the way . this is incorrect, you forgot to remove the mouseover handler when you set the draggable. I'll correct the fn.liveDraggable accordingly.
-
Yises about 12 yearsIncredibly easy, its the simplest solution. Congratulations
-
Phil almost 12 yearsAlso just found this whilst trying to solve a similar problem. Excellent solution!
-
mexique1 over 11 yearsBetter than storing data in elements, why not rely on the presence of the .ui-draggable CSS class ? I think this is lighter
-
Luke about 11 yearscouldn´t u use delegate instead. there you can specify an additional selector.
-
Dehalion over 10 yearsNowadays you should use
this.on('mouseover', selector, ...)
instead ofthis.live('mouseover', ...)