Question

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.

Was it helpful?

Solution

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

OTHER TIPS

This is a sample of code that perfectly worked for me

$('.gadgets-column').live('mouseover',function(){
    $(this).draggable();
});

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

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.

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.

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

$("html divs to drag").appendTo("#layoutDiv").draggable(options);

JSFiddle

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.

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.

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);
        }
    });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top