Good day everyone,
Given the following JSfiddle snippet: http://jsfiddle.net/abUF2/
How would it be possible to not copy back the elements from the right side to the left side when removing them from the right side (i.e. just making them disappear instead of copy back)?
Thank you very much for your help.
var received = false;
$("ul").on('mousedown', 'li', function (e) {
if ((e.ctrlKey || e.metaKey) ) {
if ($(this).next('li').hasClass('pholder'))
$(this).next('li').remove();
else
$(this).after($(this).clone().addClass('pholder').hide());
}
else{
if ($(this).next('li').hasClass('pholder')) { }
else $(this).after($(this).clone().addClass('pholder').removeClass('ui-selected').hide());
}
});
$("ul").on('click', 'li', function (e) {
if (e.ctrlKey || e.metaKey) {
$(this).toggleClass("selected");
} else {
$(this).addClass("selected").siblings().removeClass('selected');
}
}).sortable({
connectWith: "ul",
delay: 150, //Needed to prevent accidental drag when trying to select
revert: 0,
helper: function (e, item) {
//Basically, if you grab an unhighlighted item to drag, it will deselect (unhighlight) everything else
if (!item.hasClass('selected')) {
item.addClass('selected').siblings().removeClass('selected');
}
//////////////////////////////////////////////////////////////////////
//HERE'S HOW TO PASS THE SELECTED ITEMS TO THE `stop()` FUNCTION:
//Clone the selected items into an array
var elements = item.parent().children('.selected').clone();
//Add a property to `item` called 'multidrag` that contains the
// selected items, then remove the selected items from the source list
item.data('multidrag', elements).siblings('.selected').remove();
//Now the selected items exist in memory, attached to the `item`,
// so we can access them later when we get to the `stop()` callback
//Create the helper
var helper = $('<li/>');
return helper.append(elements);
},
start: function (event, ui) {
$('.pholder').show();
},
receive: function (event, ui) {
received = true;
},
stop: function (e, ui) {
if (!received) {
$('.pholder').remove();
}
else {
received = false;
$('.pholder').removeClass('pholder');
}
//Now we access those items that we stored in `item`s data!
var elements = ui.item.data('multidrag');
//`elements` now contains the originally selected items from the source list (the dragged items)!!
//Finally I insert the selected items after the `item`, then remove the `item`, since
// item is a duplicate of one of the selected items.
ui.item.after(elements).remove();
}
});
ul {
border:1px solid Black;
width:200px;
height:200px;
display:inline-block;
vertical-align:top
}
li {
background-color:Azure;
border-bottom:1px dotted Gray
}
li.selected {
background-color:GoldenRod
}
<p>Multi-select Drag</p>
<p>
<kbd>Click</kbd> to select individual items<br />
<kbd>Ctrl + Click</kbd> to select multiple items
</p>
<br />
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
<ul>
<li>Four</li>
<li>Five</li>
<li>Six</li>
</ul>
Related
I'm trying to make an exam application which has drag & drop question type that the user might dragging correct elements to correct droppable boxes. Totally, I need get dropped elements/items id's as array or another and insert to mysql with php. I did something are below:
Javascript
$(".dragging-items .draggable-item").draggable({
helper: "clone",
opacity: 0.5,
scroll:true,
refreshPositions: true,
start: function( event, ui ) {
(this).addClass("dragging");
},
stop: function( event, ui ) {
$(this).removeClass("dragging");
},
});
$(".dragging-items").droppable({
hoverClass: "drop-hover",
drop:function(event, ui) {
ui.draggable.detach().appendTo($(this));
}
});
$(".droppable-list").droppable({
drop:function(event, ui) {
ui.draggable.detach().appendTo($(this));
var drag_id = $(ui.draggable).attr("id");
var drop_id = event.target.id;
var $tbox = $("input[name=droppable-list-"+ drop_id +"]");
var current_data = $tbox.val();
var new_data = current_data + drag_id + ", ";
$tbox.val(new_data);
},
});
HTML
<ul class="dragging-items">
<li class="draggable-item" id="1"> Item-1 </li>
<li class="draggable-item" id="2"> Item-2 </li>
<li class="draggable-item" id="3"> Item-</li>
</ul>
<div class="drag-drop">
<div class="droppable-title"> Box 1 </div>
<div class="droppable-item">
<div class="droppable-list" id="1"></div>
</div>
<input type="text" class="droppable-input" name="droppable-list-1">
</div>
<div class="droppable-title"> Box 2 </div>
<div class="droppable-item">
<div class="droppable-list" id="2"></div>
</div>
<input type="text" class="droppable-input" name="droppable-list-2">
</div>
</div>
JsFiddle
https://jsfiddle.net/7e568v2y/
I found a number of oddities in CSS that may want to be corrected. A lot of missed ;, but that's not the main focus. Also, you have a number of repeated ID attributes and these must be unique in HTML. Consider the following code.
$(function() {
function dropToArray(dropObj) {
var results = [];
$(".draggable-item", dropObj).each(function(i, el) {
results.push($(el).data("drag-id"));
});
return results;
}
function updateDropList(dropObj) {
var dropped = dropToArray(dropObj);
var $tbox = $("input[name=droppable-list-" + dropObj.attr("id") + "]");
$tbox.val(dropped.join(","));
}
$(".dragging-items .draggable-item").draggable({
helper: "clone",
opacity: 0.5,
scroll: true,
refreshPositions: true,
start: function(event, ui) {
$(this).addClass("dragging");
},
stop: function(event, ui) {
$(this).removeClass("dragging");
},
});
$(".dragging-items").droppable({
hoverClass: "drop-hover",
drop: function(event, ui) {
ui.draggable.detach().appendTo($(this));
}
});
$(".droppable-list").droppable({
drop: function(event, ui) {
var $this = $(this);
if ($this.find(".droppable-list").length >= 2) {
ui.draggable.draggable("option", "revert", true);
return;
} else {
ui.draggable.detach().appendTo($(this));
setInterval(function() {
$(".droppable-list").each(function(i, el) {
updateDropList($(el));
});
}, 100);
}
},
});
});
Always best to create a few simple functions if you're going to be doing something often. I created two, one to iterate the container and build an array of the specific ID. To help ensure the same data comes back, I added the data-drag-id attribute. Now we can have unique IDs and still retain the ID Number for each item.
Working example: https://jsfiddle.net/Twisty/t1a40Lsn/22/
As you can see, when an item is dragged and dropped, it updates the field for all the lists. This addresses an issue if the user moves it from one box to another. Since the data is in an Array, we can simple use .join() to make a nice well formatted string of data.
I have two lists (div or table elements) in which I can drag & drop items from one to the other, and its working fine. But I want a to drop a copy of selected items form source div NOT removing it from the source list.
Any solution?
HTML Code:
<div class="demo">
<p>Available Boxes (click to select multiple boxes)</p>
<ul id="draggable">
<li>Box #1</li>
<li>Box #2</li>
<li>Box #3</li>
<li>Box #4</li>
</ul>
<p>My Boxes</p>
<ul id="droppable">
</ul>
</div>
Jquery Code:
$(document).ready(function() {
var selectedClass = 'ui-state-highlight',
clickDelay = 600,
// click time (milliseconds)
lastClick, diffClick; // timestamps
$("#draggable li")
// Script to deferentiate a click from a mousedown for drag event
.bind('mousedown mouseup', function(e) {
if (e.type == "mousedown") {
lastClick = e.timeStamp; // get mousedown time
} else {
diffClick = e.timeStamp - lastClick;
if (diffClick < clickDelay) {
// add selected class to group draggable objects
$(this).toggleClass(selectedClass);
}
}
})
.draggable({
revertDuration: 10,
// grouped items animate separately, so leave this number low
containment: '.demo',
start: function(e, ui) {
ui.helper.addClass(selectedClass);
},
stop: function(e, ui) {
// reset group positions
$('.' + selectedClass).css({
top: 0,
left: 0
});
},
drag: function(e, ui) {
// set selected group position to main dragged object
// this works because the position is relative to the starting position
$('.' + selectedClass).css({
top: ui.position.top,
left: ui.position.left
});
}
});
$("#droppable, #draggable").sortable().droppable({
drop: function(e, ui) {
$('.' + selectedClass).appendTo($(this)).add(ui.draggable) // ui.draggable is appended by the script, so add it after
.removeClass(selectedClass).css({
top: 0,
left: 0
});
}
});
});
Live Link: http://jsfiddle.net/T68Fn/
I have multiple jquery ui sortable lists that are connected and get balanced manually to N number of items whenever items are received by one list - just like in this answer: https://stackoverflow.com/a/13754827/27497
However, it appears that when you manually move items between lists (using jquery's .appendTo() or .prependTo()), these changes aren't detected by the jquery ui sortable library, and thus when you use the "cancel" command to revert the state, the manually moved items aren't placed back into their original list.
Is there a proper way to manually move an item from one list to another so that the sortable library is able to move the item back when you call $(".my-lists-selector").sortable("cancel");
Here is an example of how the items don't revert when you call .sortable("cancel") - just click the red cancel button after moving items from one list to another: http://jsfiddle.net/SUffL/3/
$(function() {
$( ".connectedSortable" ).sortable({
connectWith: ".connectedSortable",
update: function(event, ui) {
var ul1 = $("#ul1 li");
var ul2 = $("#ul2 li");
var ul3 = $("#ul3 li");
checkul1(ul1, ul2, ul3);
checkul2(ul1, ul2, ul3);
checkul3(ul1, ul2, ul3);
}
}).disableSelection();
$("#cancel-btn").click(function(){
$(".connectedSortable").sortable("cancel");
});
});
function checkul1(ul1, ul2, ul3) {
if (ul1.length > 5) {
ul1.last().prependTo(ul2.parent());
}
}
function checkul2(ul1, ul2, ul3) {
if (ul2.length > 5) {
if (ul1.length < 5) {
ul2.first().appendTo(ul1.parent());
} else {
ul2.last().prependTo(ul3.parent());
}
}
}
function checkul3(ul1, ul2, ul3) {
if (ul3.length > 5) {
ul3.first().appendTo(ul2.parent());
checkul2(ul1, ul2, ul3);
}
}
Here is a solution that stores the manually moved item along with list it started in and list it is moved to. Within the receive event handler the 2 lists are available as ui.sender and this. I created a simple balanceLists function to handle the manual move and the cancel of same
$(function () {
var listChange = {
startList: null,
item: null,
endList: null
}
$(".connectedSortable").sortable({
connectWith: ".connectedSortable",
receive: function (event, ui) {
listChange = {
startList: ui.sender,
item: ui.item,
endList: $(this)
}
balanceLists($(this), ui.sender)
}
}).disableSelection();
$("#cancel-btn").click(function () {
if (listChange.item) {
balanceLists(listChange.startList, listChange.endList)
$(".connectedSortable").sortable("cancel").sortable("refresh");
listChange.item=null;
}
});
});
function balanceLists($from, $to) {
$to.append($from.find('li').last())
}
DEMO: http://jsfiddle.net/SUffL/8/
This allows to undo one move with cancel button.
I'm trying to select more than one item in a jQuery sortable set and then move the selected items around together.
Here's my weak beginning of an attempt to make it work. And here's the code:
HTML:
<div class="container">
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>
<div>five</div>
</div>
JS:
$('.container div').draggable({
connectToSortable: '.container',
//How do I drag all selected items?
helper: function(e, ui) {
return $('.selected');
}
});
$('.container').sortable({
axis: 'y',
//How do I sort all selected items?
helper: function(e, ui) {
return $('.selected');
}
});
$('.container div').live('click', function(e) {
$(this).toggleClass('selected');
});
CSS:
body{background-color:#012;font-family:sans-serif;text-align:center;}
div{margin:5px 0;padding:1em;}
.container{width:52%;margin:1in auto;background-color:#555;border-radius:.5em;box-shadow:0 0 20px black;}
.container div{background-color:#333;color:#aaa;border:1px solid #777;background-color:#333;color:#aaa;border-radius:.25em;cursor:default;height:1em;}
.container div:hover{background-color:#383838;color:#ccc;}
.selected{background-color:#36a !important;border-color:#036 !important;color:#fff !important;font-weight:bolder;}
I don't know if I'm headed in the right direction or not. I can't find an example of this anywhere online. Just lots of related questions. Does anyone know how?
For example, if I've selected items 4 and 5 out of a list of 6. I want to be able to drag 4 and 5 to the top of the set to get this order - 4 5 1 2 3 6 - Or if I selected 5 and 1 and drag them to the bottom - 2 3 4 6 1 5
This seems to work with the multisortable plugin. Code below. Or see jsFiddle.
// ctrl + click to select multiple
$('.container').multisortable({
stop: function(e, ui) {
var $group = $('.ui-multisort-grouped').not(ui.item);
$group.clone().insertAfter($(ui.item));
$group.each(function() {
$(this).removeClass('ui-multisort-grouped');
});
$group.remove();
}
});
But what if multisortable breaks with future jQuery versions?
Modifying my answer here (according to your HTML and CSS) :
Select items to sort
Create a custom helper
Hide the selected items until sort is done
Resize the helper and placeholder according to the selection
Manually detach selected items from the current position and attach them to the new position after sort
Show the hidden items (undo step 3) after step5
$(function () {
$('.container').on('click', 'div', function () {
$(this).toggleClass('selected');
});
$(".container").sortable({
revert: true,
helper: function (e, item) {
if (!item.hasClass('selected')) item.addClass('selected');
var elements = $('.selected').not('.ui-sortable-placeholder').clone();
var helper = $('<div/>');
item.siblings('.selected').addClass('hidden');
return helper.append(elements);
},
start: function (e, ui) {
var elements = ui.item.siblings('.selected.hidden').not('.ui-sortable-placeholder');
ui.item.data('items', elements);
var len = ui.helper.children().length;
var currentHeight = ui.helper.height()
var itemHeight = ui.item.height() + 32; // 32 = 16x2 padding
ui.helper.height(currentHeight + (len * itemHeight))
ui.placeholder.height((len * itemHeight))
},
receive: function (e, ui) {
ui.item.before(ui.item.data('items'));
},
stop: function (e, ui) {
ui.item.siblings('.selected').removeClass('hidden');
$('.selected').removeClass('selected');
}
});
});
Updated Fiddle
I have a div which contains two elements which dont fill up that div. I want selecting the elements to select the containing div instead. Also, I want that clicking in the div but outside the elements doesnt select the element (and triggers a deselect). How do i do this?
fiddle: http://jsfiddle.net/U5cmy/1/
$("#all").on("mousedown", function(event) {
if (!$(event.target).is(".item-top, .item-bottom") && !$(event.target).hasClass("ui-selected")) {
event.stopImmediatePropagation();
return false;
}
});
$('#all').selectable({
start: function(event, ui) {
$(this).data("isDeselect", $(event.target).is(".item"))
},
selected: function(e, ui) {
if ($(this).data("isDeselect") === true) {
$(ui.selected).removeClass("ui-selected");
ui.selected = null;
}
}
});
fiddle: http://jsfiddle.net/1stein/sNMw3/