Search code examples
jqueryeventsclonedraggablejquery-ui-sortable

jQuery Click event not working after draggable is dropped into sortable


Using the example provided in jQueryUI tutorial: jQuery UI Draggable + Sortable

When I drag and drop the draggable <li> element into the sortable list it will be cloned. Which is working as expected. The clone element can then also be re-sorted. This is also working as expected. The problem is that the "click" event of the newly created cloned element doesn't fire. To illustrate this simply modify the sortable.html by inserting the four lines of code below to the end of the function.

$("li").on("click", function(event){
   var clicked_element_class = $(this).attr('class');
   alert(clicked_element_class);
});
    <!doctype html>

This will trigger an alert showing the element's class attribute every time a <li> element is clicked. However the alert is not triggered when clicking on the cloned element that has been created by dragging and dropping the draggable element into the list. This shows me that the click event is not fired for a particular clone after this clone has been created and added to the sortable list. It seems actually that the click event has been removed from the clone, or that it is not recognized by the existing $("li").on("click", ... function, since it was added to the DOM at a later point. How can I trigger the same (existing) $("li").on("click", ... function with the alert via the "click" event for a newly created clone in the sortable list? Any help is very much appreciated.

Update:

Here is the entire source code:

            <!doctype html>
            <html lang="en">
            <head>
              <meta charset="utf-8" />
              <title>jQuery UI Draggable + Sortable</title>
              <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
              <script src="http://code.jquery.com/jquery-1.8.3.js"></script>
              <script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
              <link rel="stylesheet" href="/resources/demos/style.css" />
              <style>
              ul { list-style-type: none; margin: 0; padding: 0; margin-bottom: 10px; }
              li { margin: 5px; padding: 5px; width: 150px; }
              </style>
              <script>
              $(function() {
                var cloneCache;      
                $( "#sortable" ).sortable({
                  revert: true,
                });
                $( ".ui-state-highlight" ).draggable({
                  connectToSortable: "#sortable",
                  helper: "clone",
                  revert: "invalid"
                });
                $( "ul, li " ).disableSelection();

                $("li").on("click", function(event){
                  var clicked_element_class = $(this).attr('class');
                  alert(clicked_element_class);
                });
               });
               </script>
              </head>
             <body>

Solution

  • This is because you are only applying the click listener to existing li elements.

    You want to use the selector parameter for the .on() function to add these listeners dynamically:

    Replace this:

    $('li').on('click', function(event) {
        var clicked_element_class = $(this).attr('class');
        alert(clicked_element_class);
    });
    

    With this:

    $('ul, ol').on('click', 'li', function(event) {
        var clicked_element_class = $(this).attr('class');
        alert(clicked_element_class);
    });
    

    Update 1

    To apply this click listener to li and a and p elements change your selector parameter:

    $('ul, ol').on('click', 'li, li a, li p', function(event) {
        var clicked_element_class = $(this).attr('class');
        alert(clicked_element_class);
    });
    

    This applies the listener to li elements, a elements that are children of li elements and p elements that are children of li elements.

    Note this listener will return the class of the each element, not the li class. That is, when an a tag is clicked, the a class will be returned, not the li class.

    Also, perhaps a better way to apply this jQuery on listener is to apply it to the #sortable element:

    $('#sortable').on('click', 'li, li a, li p', function(event) {
        var clicked_element_class = $(this).attr('class');
        alert(clicked_element_class);
    });