jQuery Drag And Drop Using Live Events
Asked Answered
G

10

41

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.

Geraldgeralda answered 26/11, 2009 at 19:2 Comment(1)
What does if (!jQuery(this).data("init")) { jQuery(this).data("init", true);} do?Blank
L
45

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})
Launderette answered 28/7, 2010 at 2:5 Comment(7)
This broke my js altogether. Do you need to put this somewhere in particular to extend the JQuery functionality?Aricaarick
You need to declare it after you load jQuery and before you use it in your code. What error are you getting?Launderette
You forgot to return the element for chainingHibbert
by the way . this is incorrect, you forgot to remove the mouseover handler when you set the draggable. I'll correct the fn.liveDraggable accordingly.Thunderpeal
Also just found this whilst trying to solve a similar problem. Excellent solution!Stickney
Better than storing data in elements, why not rely on the presence of the .ui-draggable CSS class ? I think this is lighterMansell
Nowadays you should use this.on('mouseover', selector, ...) instead of this.live('mouseover', ...)Anhinga
C
21

This is a sample of code that perfectly worked for me

$('.gadgets-column').live('mouseover',function(){
    $(this).draggable();
});
Chandlery answered 11/10, 2010 at 7:25 Comment(4)
it's an easy solution, but draggable is executed on all DOM elements with gadgets-column class everytime you hover one of them...Surrogate
@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).Thunderpeal
@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.Surrogate
Incredibly easy, its the simplest solution. CongratulationsMagic
J
10

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})

Joe answered 13/4, 2010 at 21:21 Comment(0)
B
7

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.

Brunswick answered 17/5, 2011 at 8:6 Comment(2)
Yes, 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')){...}"?Launderette
couldn´t u use delegate instead. there you can specify an additional selector.Immersionism
D
4

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.

Dunt answered 18/7, 2013 at 20:51 Comment(0)
U
1

An example:

Turkish:

<div id="diyalogKutusu">
    <div id="diyalog-baslik">..baslik..</div>
    <div id="icerik">..icerik..</div>
</div>

$(document).on("mouseover", "#diyalogKutusu", function() {
    $(this).draggable({ handle: '#diyalog-baslik' });
});

English:

<div id="dialogBox">
    <div id="dialogBox-title">..title..</div>
    <div id="content">..content..</div>
</div>

$(document).on("mouseover", "#dialogBox", function() {
    $(this).draggable({ handle: '#dialogBox-title' });
});

Note: You can use on() instead of live() or delegate. The on() has good performance than others

Unpleasantness answered 8/10, 2012 at 0:44 Comment(0)
W
1
$("html divs to drag").appendTo("#layoutDiv").draggable(options);

JSFiddle

Wulfenite answered 4/12, 2013 at 12:20 Comment(0)
M
0

An old question. But threedubmedia has drag and drop plugin with live (as of v 1.7 known as simply "on") support. http://threedubmedia.com/code/event/drop Haven't used it to much so I can't account for it performance, etc. but looks reasonable.

Mouthpart answered 15/8, 2012 at 14:34 Comment(0)
U
0

Another option is to mix the mouseover handler with a removable class, like so:

$('.outer-container').on('mouseover', '.my-draggable.drag-unbound', function(e) {
  $(this).draggable().removeClass('drag-unbound');
});

It's fairly straightforward and resolves some of the issues that other answers have with re-binding over and over as you mouseover.

Unanswerable answered 29/10, 2014 at 20:20 Comment(0)
S
0

An updated version that does not use live as it is deprecated:

function liveDraggable(selector, options) {
    $(document).on('mouseover', selector, function () {
        if (!$(this).data("init")) {
            $(this).data("init", true);
            $(this).draggable(options);
        }
    });
}
Snuck answered 7/12, 2014 at 17:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.