Monday, April 23, 2012

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


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?




<!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({
update: function() { console.log('update') },
delay: 30
});


$('#my_sortable li').click(function () {
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>


Source: Tips4all

7 comments:

  1. 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>

    ReplyDelete
  2. 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 identical 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..

    ReplyDelete
  3. 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 ...

    ReplyDelete
  4. 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>

    ReplyDelete
  5. This solution was not working so fine for me in IE6 (I require also compatibility to this browser).
    I used the alternative solution given here.

    ReplyDelete
  6. the "helper : 'clone'" trick doesn't work in chrome. The onclick event doesn't fire ever.

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

    ReplyDelete