Search code examples
jqueryjquery-uijquery-ui-draggablejquery-ui-droppable

JQuery UI : Sortable - Which event should I use?


I've a problem while working with JQuery UI. What I'm trying to achieve is this:

  • I have a sortable list ( .form_container ), with objects. When their position are changed, ajax call updates the DB.
  • Outside of this list, I've got "text items" ( .create_item ). When those items are being dropped on the sortable list, I want to make an ajax call that will give me the content so I can transform my simple item into an object.
  • THEN, because a new object has been added, I want the ajax calls for position being fired. But not before my new object is properly loaded.

I hope I'm clear enough...

So first, I though about doing something like that

First Attempt :

$(".create_item").draggable({
  containment: 'window',
  connectToSortable: ".form_container",
  helper: "clone",
});
$(".form_container").droppable({
  accept: ".create_item",
  tolerance: 'fit',
  over: function(event,ui) {
    // Something here
  },
  drop: function(event,ui) {
    // Ajax calls that changes my item into an object
  }
});
$(".form_container").sortable({
  axis: "y",
  containment: ".form_container",
  revert: true,
  update: function(event, ui){
    // Ajax calls that update positions in DB
  }         
});

Problem is, connectToSortable also triggers the drop event so this event is called twice thus causing trouble.

So I've followed someone's advice on SOF, and changed my code for something like that.

Second Attempt :

$(".create_item").draggable({
  containment: 'window',
  connectToSortable: ".form_container",
  helper: "clone",
});
$(".form_container").droppable({
  accept: ".create_item",
  tolerance: 'fit',
  over: function(event,ui) {
    // Something here
  }
  // No more drop function
});
$(".form_container").sortable({
  axis: "y",
  containment: ".form_container",
  revert: true,
  update: function(event, ui){
    // Ajax calls that update positions in DB
  },
  receive: function(event,ui) {
    // Ajax calls that changes my item into an object
  }         
});

Problem is, the update event is triggered before the receive event is finished and my item hasn't been transformed properly into a nice object.

That's about everything, can someone help me?


Solution

  • Regarding your first attempt, as far as I know, double drop call is known issue (http://url.ba/o88p). I can only suggest some workaround by declaring some global variable (counter), and then use it to make call every second time:

      drop: function(event,ui) {
        if (counter++%2) {
            // Ajax calls that changes my item into an object
        }
      }
    

    Regarding your second attempt I think solution is a little bit elegant. First, declare your update method using bind (only if you bind it this way you can trigger it manually).

    var _updateFunction = function(event, ui){
        // logic for update, ajax calls, etc.
    };
    $('.form_container').bind('sortupdate', _updateFunction);
    

    Now, create received function that will look something like this:

    receive: function(event,ui) {
        // don't let update be called
        $('.form_container').unbind('sortupdate');
    
        $
          // call to create object using ajax
          .ajax()
          // when this call is finished
          .done(function() {
              $('.form_container')
                  .bind('sortupdate', _updateFunction)
                  .trigger('sortupdate');
          })
    }
    

    Here is this example in jsfiddle http://jsfiddle.net/7jPAv/