why unselection is not working for multiple items with selectable and draggable

Viewed 156

i want my unselection of list items work as smooth as .selectable() without .draggable()

My expectation is something like below gif with selectable and draggable combined:

enter image description here

here above code without draggable:

   $("#selectable").selectable();
  #feedback {
      font-size: 1.4em;
  }
  #selectable .ui-selecting {
      background: #FECA40;
  }
  #selectable .ui-selected {
      background: #F39814;
      color: white;
  }
  #selectable {
      list-style-type: none;
      margin: 0;
      padding: 0;
      width: 60%;
  }
  #selectable li {
      margin: 3px;
      padding: 0.4em;
      font-size: 1.4em;
      height: 18px;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>

<ol id="selectable">
    <li class="ui-widget-content">Item 1</li>
    <li class="ui-widget-content">Item 2</li>
    <li class="ui-widget-content">Item 3</li>
    <li class="ui-widget-content">Item 4</li>
    <li class="ui-widget-content">Item 5</li>
    <li class="ui-widget-content">Item 6</li>
    <li class="ui-widget-content">Item 7</li>
</ol>

Question: the below combined selectable and draggable selection and unselection is not working as above code with only selectable

here is what i have tried:

$(function() {
    $( "#selectable" ).selectable({
           start: function (event, ui) {
                 /* $('.ui-widget-content').draggable('destroy') */;
             },
       stop: function(event,ui){
           $('.ui-widget-content').draggable({
               drag: function(event,ui){
                  console.log('dragging....');
                  $('#multiple_selected_rows').remove();
                  var elem = document.createElement("div");
                  elem.id = "multiple_selected_rows";
                  elem.innerText = $('li.ui-selected').length+" items";
                  document.body.appendChild(elem);
                  
                   $("#multiple_selected_rows").css({ 'top': event.clientY + 10, 'left': event.clientX + 10 });
               }
           });
           $( "#selectable" ).selectable();
       }
    });
    
    $('#droppable').droppable({
        accept: '.ui-widget-content',
        greedy: true,
        drop: function (event, ui) {
           $('#multiple_selected_rows').remove();
        }   
    });
 });
#feedback { font-size: 1.4em; }
  #selectable .ui-selecting { background: #FECA40; }
  #selectable .ui-selected { background: #F39814; color: white; }
  #selectable { list-style-type: none; margin: 0; padding: 0; /*width: 60%;*/ padding:22px; border: solid 1px #0973c7;}
  #selectable li { margin: 8px; padding:10px; border:solid 1px #CCC;}
  .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } 

#main-container{
    display: flex;
    justify-content: space-between;
}

div#main-container .demo {
    width: 50%;
    margin-right: 7px;
}

div#main-container #droppable {
    flex: 1;
    border: 1px solid red;
}

#multiple_selected_rows{
   position:absolute;
   width: 90px;
   height:40px;
   background:red;
   color: #fff;
   text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>


<div id="main-container">
     <div class="demo">
        <ol id="selectable">
          <li class="ui-widget-content">Item 1</li>
          <li class="ui-widget-content">Item 2</li>
          <li class="ui-widget-content">Item 3</li>
          <li class="ui-widget-content">Item 4</li>
          <li class="ui-widget-content">Item 5</li>
          <li class="ui-widget-content">Item 6</li>
          <li class="ui-widget-content">Item 7</li>
        </ol>
    </div>
    <div id="droppable">
        
    </div>
</div>

Please help me thanks in advance!!!!!

1 Answers

Note: The way you are drag selecting multiple items and then immediately selecting only a single item by clicking on it (as shown in the gif) will not be possible if you are going to drag the selected items to another box. You can either drag a selection with selectable(), or drag, i.e. move, your selected items with draggable(), not both.


Your selectable() and draggable() methods are competing with one another for the same mouse events. So instead of setting them up on page load, try this:

In the selectable() stop callback, wrap the selected elements in a div:

$('.ui-selected').wrapAll('<div id="dragSet"></div>');

Then call draggable() on #dragSet. Now this call will take precedence over the selectable() mouse events for the selected items.

In the draggable() stop callback, append the selected items to #droppable and remove their .ui-selected class.

$('#droppable').append( $('#dragSet') );
$('#dragSet').contents().unwrap();
$('#droppable li').removeClass('ui-selected'); 

Finally, add some logic to the selectable() start callback to prevent double wrapping your selection.

if ( $('#dragSet').children().length > 0 ) $('#dragSet').contents().unwrap();
else $('#dragSet').remove(); 

See working example below:

$(function() {
  $("#selectable").selectable({
    start: function(event, ui) {
      if ($('#dragSet').children().length > 0) $('#dragSet').contents().unwrap();
      else $('#dragSet').remove();
    },
    stop: function(event, ui) {
      $('.ui-selected').wrapAll('<div id="dragSet"></div>');
      $('#dragSet').draggable({
        stop: function(event, ui) {
          $('#droppable').append($('#dragSet'));
          $('#dragSet').contents().unwrap();
          $('#droppable li').removeClass('ui-selected');
        }
      });
    }
  });
});
#feedback {
  font-size: 1.4em;
}

#selectable .ui-selecting {
  background: #FECA40;
}

#selectable .ui-selected {
  background: #F39814;
  color: white;
}

#selectable {
  list-style-type: none;
  margin: 0;
  padding: 0;
  /*width: 60%;*/
  padding: 22px;
  border: solid 1px #0973c7;
}

#selectable li {
  margin: 8px;
  padding: 10px;
  border: solid 1px #CCC;
}

.ui-selectable-helper {
  position: absolute;
  z-index: 100;
  border: 1px dotted black;
}

#main-container {
  display: flex;
  justify-content: space-between;
}

div#main-container .demo {
  width: 50%;
  margin-right: 7px;
}

div#main-container #droppable {
  flex: 1;
  border: 1px solid red;
}

#multiple_selected_rows {
  position: absolute;
  width: 90px;
  height: 40px;
  background: red;
  color: #fff;
  text-align: center;
}

#droppable li.ui-widget-content {
  margin: 8px;
  padding: 10px;
  border: solid 1px #ccc;
  color: white;
  background: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>


<div id="main-container">
  <div class="demo">
    <ol id="selectable">
      <li class="ui-widget-content">Item 1</li>
      <li class="ui-widget-content">Item 2</li>
      <li class="ui-widget-content">Item 3</li>
      <li class="ui-widget-content">Item 4</li>
      <li class="ui-widget-content">Item 5</li>
      <li class="ui-widget-content">Item 6</li>
      <li class="ui-widget-content">Item 7</li>
    </ol>
  </div>
  <div id="droppable">

  </div>
</div>


Bonus:

To drag back and forth, repeat the same JS and swap #selectable with #droppable.

$(function() {
  $("#selectable").selectable({
    start: function(event, ui) {
      if ($('#dragSet').children().length > 0) $('#dragSet').contents().unwrap();
      else $('#dragSet').remove();
    },
    stop: function(event, ui) {
      $('.ui-selected').wrapAll('<div id="dragSet"></div>');
      $('#dragSet').draggable({
        stop: function(event, ui) {
          $('#droppable').append($('#dragSet'));
          $('#dragSet').contents().unwrap();
          $('#droppable li').removeClass('ui-selected');
        }
      });
    }
  });

  $("#droppable").selectable({
    start: function(event, ui) {
      if ($('#dragSet').children().length > 0) $('#dragSet').contents().unwrap();
      else $('#dragSet').remove();
    },
    stop: function(event, ui) {
      $('.ui-selected').wrapAll('<div id="dragSet"></div>');
      $('#dragSet').draggable({
        stop: function(event, ui) {
          $('#selectable').append($('#dragSet'));
          $('#dragSet').contents().unwrap();
          $('#selectable li').removeClass('ui-selected');
        }
      });
    }
  });
});
#feedback {
  font-size: 1.4em;
}

#selectable .ui-selecting,
#droppable .ui-selecting {
  background: #FECA40;
}

#selectable .ui-selected,
#droppable .ui-selected {
  background: #F39814;
  color: white;
}

#selectable,
#droppable {
  list-style-type: none;
  margin: 0;
  padding: 0;
  padding: 22px;
  border: solid 1px #0973c7;
}

#selectable li,
#droppable li {
  margin: 8px;
  padding: 10px;
  border: solid 1px #CCC;
}

.ui-selectable-helper {
  position: absolute;
  z-index: 100;
  border: 1px dotted black;
}

#main-container {
  display: flex;
  justify-content: space-between;
}

div#main-container .demo {
  width: 50%;
  margin-right: 7px;
}

div#main-container #droppable {
  flex: 1;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>


<div id="main-container">
  <div class="demo">
    <ol id="selectable">
      <li class="ui-widget-content">Item 1</li>
      <li class="ui-widget-content">Item 2</li>
      <li class="ui-widget-content">Item 3</li>
      <li class="ui-widget-content">Item 4</li>
      <li class="ui-widget-content">Item 5</li>
      <li class="ui-widget-content">Item 6</li>
      <li class="ui-widget-content">Item 7</li>
    </ol>
  </div>
  <div id="droppable">

  </div>
</div>


Selectable and Draggable with selection as shown in the gif:

Normally, you would need to click on the selected items in order to drag them. But since you want to be able to click on them to make a new selection, you'll need to add another element as a handle to drag them by.

$(function() {
  $( "#selectable" ).selectable({      
    start: function (event, ui) {
        if ( $('#dragSet').children().length > 0 ) {
          $('#dragHandle').remove();
          $('#dragSet').contents().unwrap();
        }
        else $('#dragSet').remove();        
    },
    stop: function(event,ui){        
      $('.ui-selected').wrapAll('<div id="dragSet"></div>');
      $('#dragSet').append('<div id="dragHandle">Drag Me</div>');
      $('#dragHandle').on('mouseenter', function() {
        $('#dragSet').draggable({
          stop: function(event, ui){            
            $('#droppable').append( $('#dragSet') );
            $('#dragHandle').remove();
            $('#dragSet').contents().unwrap();
            $('#droppable li').removeClass('ui-selected');          
          }
        });
      }).on('mouseleave', function() {
        $('#dragSet').draggable('destroy');
      }); 
    }
  });

  $( "#droppable" ).selectable({      
    start: function (event, ui) {
        if ( $('#dragSet').children().length > 0 ) {
          $('#dragHandle').remove();
          $('#dragSet').contents().unwrap();          
        }
        else $('#dragSet').remove();        
    },
    stop: function(event,ui){        
      $('.ui-selected').wrapAll('<div id="dragSet"></div>');
      $('#dragSet').append('<div id="dragHandle">Drag Me</div>');
      $('#dragHandle').on('mouseenter', function() {
        $('#dragSet').draggable({
          stop: function(event, ui){            
            $('#selectable').append( $('#dragSet') );
            $('#dragHandle').remove();
            $('#dragSet').contents().unwrap();
            $('#selectable li').removeClass('ui-selected');          
          }
        });
      }).on('mouseleave', function() {
        $('#dragSet').draggable('destroy');
      });
    }
  });
 });
#feedback { 
  font-size: 1.4em; 
}

#selectable .ui-selecting,
#droppable .ui-selecting { 
  background: #FECA40; 
}

#selectable .ui-selected,
#droppable .ui-selected { 
  background: #F39814; 
  color: white; 
}

#selectable, 
#droppable { 
  list-style-type: none; 
  margin: 0; 
  padding: 0; 
  padding:22px; 
  border: solid 1px #0973c7;
}

#selectable li,
#droppable li { 
  margin: 8px; 
  padding:10px; 
  border:solid 1px #CCC;
}

.ui-selectable-helper { 
  position: absolute; 
  z-index: 100; 
  border:1px dotted black; 
} 

#main-container{
  display: flex;
  justify-content: space-between;
}

div#main-container .demo {
  width: 50%;
  margin-right: 7px;
}

div#main-container #droppable {
  flex: 1;
  border: 1px solid red;
}

#dragSet {
  position: relative;
}

#dragHandle {
  position: absolute;
  top: 4px;
  right: 12px;
  background-color: red;
  color: white;
  padding: 6px;
  border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>


<div id="main-container">
  <div class="demo">
    <ol id="selectable">
      <li class="ui-widget-content">Item 1</li>
      <li class="ui-widget-content">Item 2</li>
      <li class="ui-widget-content">Item 3</li>
      <li class="ui-widget-content">Item 4</li>
      <li class="ui-widget-content">Item 5</li>
      <li class="ui-widget-content">Item 6</li>
      <li class="ui-widget-content">Item 7</li>
    </ol>
  </div>
  <div id="droppable">

  </div>
</div>

Related