8

I am trying to create a group of draggable DOM objects using jQuery UI's .draggable() that are populated through Meteor subscriptions. The code I came up with looks like

Meteor.subscribe('those_absent', function() {
     $( "li.ui-draggable" ).draggable( { revert: "invalid" } );
});
Meteor.subscribe('those_present', function() {
     $( "li.ui-draggable" ).draggable( { revert: "invalid" } );
});

These correspond with some Meteor.publish() calls, so that any time the collection changes, the .draggable() behaviour will be attached. At least, that was my intention.

However, it only works once - once one of these <li>'s has been dragged and dropped, then they are no longer draggable at all.

When the objects are dropped, I'm firing a custom event that is attached to the Template for the item like so

    $( "#c_absent .inner-drop" ).droppable({
        drop: function( event, ui ) {
            ui.draggable.trigger('inout.leave');
        }
    });


  Template.loftie_detail.events = {
      'inout.leave': function (e) {
          Lofties.update({_id:this._id}, {$set: {present: 'N' }});
      }
  };

So, my thinking is that this change to the collection on drop should propagate through the pub/sub process and re-run the .draggable() line above. But it doesn't seem to.

The complete code for this can be seen here https://github.com/sbeam/in-out/blob/master/client/inout.js and the app is live at http://inout.meteor.com/ (there are some other probably unrelated issues with items randomly losing values or disappearing from the UI altogether)

So if my understanding of how pub/sub works in Meteor is off, it would be good to know. Or is there a more efficient way to achieve this UI behavior binding that works without it?

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
sbeam
  • 4,622
  • 6
  • 33
  • 43
  • http://stackoverflow.com/questions/10453291/how-to-trigger-jquery-draggable-on-elements-created-by-templates/10509361#comment13641878_10509361 – lashleigh May 16 '12 at 17:08
  • 2
    And more recently http://stackoverflow.com/questions/10646570/how-to-handle-custom-jquery-events-in-meteor. I'm not convinced there is a clean and proper way to do it yet, but lots of people have hacks. – lashleigh May 18 '12 at 23:30
  • thanks @lashleigh - so to summarize, as of now, you need to attach `draggable()` or whatever other behavior on mouseover events, ie, at the "last" possible moment. A clean and proper way that works on touchscreens would be a good area for active research and contribution. – sbeam May 21 '12 at 14:01
  • Exactly, that is what I have seen most people use. The other way is to bind using defer after the template has rendered; which would work with touch devices, but most people aren't in favor of using the timeout hack. – lashleigh May 21 '12 at 16:34
  • The reason the `Meteor.subscribe` callback doesn't work for this is that it only fires once, when the collection is initially constituted on page load. – dgreensp May 22 '12 at 19:43
  • 3
    It sounds like we need a post-render hook for stuff like this. In the long term there should be a built-in pattern for drag and drop. – dgreensp May 22 '12 at 19:50

1 Answers1

4

The way I have implemented this in my apps is with the method shown by @lashleigh.

I have a template event that listens using code like this :

Template.myDraggableItem.events({
    'mouseover .workItem' : function() {
        $(this._id).draggable();
    }
});

Then I listen for the dragstop like this.

$('body').on('dragstop', '.myDraggableItem', function (e) {
    // Update the collection with the new position
};

You can see the app that's using this code at aduno.meteor.com

Felix Rabe
  • 4,206
  • 4
  • 25
  • 34
Braden
  • 1,548
  • 2
  • 12
  • 20
  • that seems to be the correct strategy, so accepting this (but FYI there seems to be some issue with drag & drop in your app, it stopped responding) – sbeam Oct 07 '12 at 18:51
  • 1
    Hey awesome, you're trying to do the same thing I am! Task management for Github. Meteor seems to be making drag and drop very hard while making other things easier. I'll watch your project, wish you best of luck. Btw, if you get it working, a kanban board would be killer :) – Milimetric Jan 20 '13 at 00:09
  • 2
    Check this out, someone already got something like kanban working: http://minitrello.meteor.com/ – Milimetric Jan 20 '13 at 00:26
  • @Milimetric aw shieet, that's what I'm talking about! – Andrew Mao Aug 01 '13 at 22:24
  • Meteor's not making drag & drop hard.. Just use the template built in event handlers. Also, I think a better way to bind jq is to use the Template's "rendered" hook; Template. myDraggableItem.rendered = function(){ .... } (meteor > 0.4.0) – 0x6A75616E Oct 20 '13 at 16:35