jQuery UI Sortable -- How can I cancel the click event on an item that's dragged/sorted?

JavascriptJqueryJquery Ui

Javascript Problem Overview


I have a jQuery UI Sortable list. The sortable items also have a click event attached. Is there a way to prevent the click event from firing after I drag an item?

$().ready( function () { 
 $('#my_sortable').sortable({
   update: function() { console.log('update') },
   delay: 30
 });    

 $('#my_sortable li').click(function () {    
   console.log('click');
 });                        

});

#my_sortable li {
          border: 1px solid black;
          display: block;
          width: 100px;
          height: 100px;    
          background-color: gray;
        }

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js"></script>

<ul id="my_sortable">                 
  <li id="item_1">A</li>
  <li id="item_2">B</li>
  <li id="item_3">C</li>
</ul>   

Javascript Solutions


Solution 1 - Javascript

I had the same problem and since my sortable items contained three or four clickable items (and the number was variable) binding/unbinding them on the fly didn't really seem an option. However, by incident I specified the

helper : 'clone'

option, which behaved identically to the original sortable in terms of interface but apparently does not fire click events on the dragged item and thus solves the problem. It's as much a hack as anything else, but at least it's short and easy..

Solution 2 - Javascript

If you have a reference to the click event for your li, you can unbind it in the sortable update method then use Event/one to rebind it. The event propagation can be stopped before you rebind, preventing your original click handler from firing.

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
<head> 


  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js"></script>

  <script type="text/javascript" charset="utf-8">
  	var myClick = function () {
  		console.log('click');
  	};
  	
    $().ready( function () { 

       $('#my_sortable').sortable({
         update: function(event, ui) { 
         	ui.item.unbind("click");
         	ui.item.one("click", function (event) { 
         		console.log("one-time-click"); 
         		event.stopImmediatePropagation();
         		$(this).click(myClick);
         	}); 
         	console.log('update') },
         delay: 30
       });    


       $('#my_sortable li').click(myClick);                        

     });
  </script>

  <style type="text/css" media="screen">
    #my_sortable li {
      border: 1px solid black;
      display: block;
      width: 100px;
      height: 100px;    
      background-color: gray;
    }
  </style>

</head>
<body>

      <ul id="my_sortable">                 
        <li id="item_1">A</li>
        <li id="item_2">B</li>
        <li id="item_3">C</li>
      </ul>   

</body>
</html>

Solution 3 - Javascript

If you for some reason don't want to use the helper:'clone' trick, this worked for me. It cancels the click event on an item that is dragged. jQuery adds the class ui-sortable-helper to the dragged element.

$('.draggable').click(clickCancelonDrop);
function clickCancelonDrop(event) {
    var cls = $(this).attr('class');
    if (cls.match('ui-sortable-helper'))
         return event.stopImmediatePropagation() || false;
}

Solution 4 - Javascript

$('.selector').draggable({
    stop: function(event, ui) {
        // event.toElement is the element that was responsible
        // for triggering this event. The handle, in case of a draggable.
        $( event.toElement ).one('click', function(e){ e.stopImmediatePropagation(); } );
    }
});

This works because "one-listeners" are fired before "normal" listeners. So if a one-listener stops propagation, it will never reach your previously set listeners.

Solution 5 - Javascript

The answer by mercilor worked for me a couple of caveats. The click event was actually on the handle element rather than the sorted item itself. Unfortunately the ui object, doesn't give you a reference to the handle in the update event (feature request to jquery ui?). So I had to get the handle myself. Also, I had to call preventDefault as well to stop the click action.

update: function(ev, ui) {
    var handle = $(ui.item).find('h3');
    handle.unbind("click");
    handle.one("click", function (event) {
                            event.stopImmediatePropagation();
                            event.preventDefault();
                            $(this).click(clickHandler);
                        });
    // other update code ...

Solution 6 - Javascript

Easier, use a var to know when the element is being sorted...

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head> 


  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js"></script>

  <script type="text/javascript" charset="utf-8">
    $().ready( function () {    
       $('#my_sortable').sortable({
         start: function() {
            sorting = true;
         },
         update: function() {
            console.log('update');
            sorting = false;
         },
         delay: 30
       });    


       $('#my_sortable li').click(function () {
         if (typeof(sorting) == "undefined" || !sorting) {
            console.log('click');
         }
       });                        

     });
  </script>

  <style type="text/css" media="screen">
    #my_sortable li {
      border: 1px solid black;
      display: block;
      width: 100px;
      height: 100px;    
      background-color: gray;
    }
  </style>

</head>
<body>

      <ul id="my_sortable">                 
        <li id="item_1">A</li>
        <li id="item_2">B</li>
        <li id="item_3">C</li>
      </ul>   

</body>
</html>

Solution 7 - Javascript

We can also use a flag on the stop event that and check that flag on the click event.

var isSortableCalled = false;

$('#my_sortable').sortable({
         stop: function(event, ui){
              isSortableCalled = true;
         },
         update: function() { console.log('update') },
         delay: 30
});

$('#my_sortable li').click(function () {    
       if(!isSortableCalled){
            console.log('click');
       }
       isSortableCalled = false;

});

Solution 8 - Javascript

Thanks to Elte Hupkus;

helper: 'clone' 

I have implemented the same and a sample is shown below.

$(document).ready(function() {
$("#MenuListStyle").sortable({
 helper:'clone',
 revert:true
}).disableSelection();
});

Solution 9 - Javascript

One solution is to use live() instead of normal binding, but Elte Hupkes solution rocks!!!!

Solution 10 - Javascript

$('.menu_group tbody a').click(function(){
    link = $(this).attr('href');
    window.location.href = link;
});

This solution seems to be working for me. Now i can click on clickables inside sortable elements.

Note: ".menu_group tbody" is .sortable();

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrick McElhaneyView Question on Stackoverflow
Solution 1 - JavascriptElte HupkesView Answer on Stackoverflow
Solution 2 - JavascriptAndrew ChampionView Answer on Stackoverflow
Solution 3 - JavascriptFredrik HarloffView Answer on Stackoverflow
Solution 4 - JavascriptTom de BoerView Answer on Stackoverflow
Solution 5 - JavascriptMarcoView Answer on Stackoverflow
Solution 6 - JavascriptragnarView Answer on Stackoverflow
Solution 7 - JavascriptSaurabhView Answer on Stackoverflow
Solution 8 - JavascriptTijo TomView Answer on Stackoverflow
Solution 9 - JavascriptBakaburgView Answer on Stackoverflow
Solution 10 - JavascriptRiki137View Answer on Stackoverflow