I have two divs, each containing a list of quantities and items. The items are draggable and the div containing the items is droppable. If an item of the same name appears in that div, that item cannot be dropped on that div again. Eventually I will be controlling the number of items that are moved, but I'm just trying to get this part to work for now.
The problem I'm having is that once I drop an item on the div, I can no longer drag it. I've tried adding draggable() to the new item that I am creating, but that just made things weird.
The exact same code worked when I was adding an li to a ul, but I wanted to move just the name of the item and not the quantity, so I am using divs instead of li.
Here is a jsfiddle of my code: http://jsfiddle.net/imjustabill/eJ4KH/
And here are the pertinent parts
$(function () {
$("#inventory1 .item").draggable({
appendTo: "body",
helper: "clone"
});
$("#inventory2").droppable({
drop: function (event, ui) {
var item = ui.draggable.attr("data-item");
var qty = ui.draggable.attr("data-qty");
var itemDesc = ui.draggable.text();
if (!$(this).find("[data-item='"+item+"']").length) {
$("<div class='qty'></div>").text(qty).appendTo(this);
$("<div class='item ui-draggable' data-qty='"+qty+"' data-item='"+item+"'></div>").text(itemDesc).appendTo(this);
}
}
});
$("#inventory2 .item").draggable({
appendTo: "body",
helper: "clone"
});
$("#inventory1").droppable({
drop: function (event, ui) {
var item = ui.draggable.attr("data-item");
var qty = ui.draggable.attr("data-qty");
var itemDesc = ui.draggable.text();
if (!$(this).find("[data-item='"+item+"']").length) {
$("<div class='qty'></div>").text(qty).appendTo(this);
$("<div class='item ui-draggable' data-qty='"+qty+"' data-item='"+item+"'></div>").text(itemDesc).appendTo(this);
}
}
});
});
<div id="inventory1">
<h4>Inventory 1</h4>
<div class="qty">7</div><div class="item" data-qty="7" data-item="item1">Item 1</div>
<div class="qty">5</div><div class="item" data-qty="5" data-item="item2">Item 2</div>
<div class="qty">2</div><div class="item" data-qty="2" data-item="item3">Item 3</div>
<div class="qty">9</div><div class="item" data-qty="9" data-item="item4">Item 4</div></div>
<div id="inventory2">
<h4>Inventory 2</h4>
<div class="qty">4</div><div class="item" data-qty="4" data-item="item1">Item 1</div>
<div class="qty">2</div><div class="item" data-qty="2" data-item="item5">Item 5</div></div>
Any ideas? Thank you.
The Problem is, that the Draggable calls it's destroy() on drop so you loose your dragging ability. One dirty way is to make your dropped element draggable again:
$("#inventory2").droppable({
drop: function (event, ui) {
var item = ui.draggable.attr("data-item");
var qty = ui.draggable.attr("data-qty");
var itemDesc = ui.draggable.text();
if (!$(this).find("[data-item='"+item+"']").length) {
$("<div class='qty'></div>").text(qty).appendTo(this);
$("<div class='item ui-draggable' data-qty='"+qty+"' data-item='"+item+"'></div>").text(itemDesc).draggable({appendTo: "body", helper: "clone"}).appendTo(this);
}
}
});
But it won't be droppable again.
Do you have to use draggable/droppable?
Just use jQueryUI's own Sortable with connected lists. Its already perfectly implemented to jQueryUI:
jQueryUI Sortable with connected lists
Related
I'm trying to create UI for advanced search so that the user can make search rule boxes and then drag and drop them on top of others to create a group of rule boxes. Each box has a drop event, and when one box is dropped on top of the other a new Div container is built and the two boxes are placed there. The container also has a separate drop event and allows a box to be placed in the container if it is dropped on . The problem is that when one box is in the container and the other box is placed on it, the container event occasionally is also triggered. How to prevent container event to be triggered ? Here it is some pictures of the UI :
The rule box drop event is :
$('.ruleBox').droppable({
tolerance: 'pointer',
accept: '.ruleBox,.subExpressionContainer',
drop: function (event, ui) {
let dropped = ui.draggable,
droppedOn = $(this),
droppedParent = dropped.parent();
let newId = generateID(1),
subExpressionContainer = MakeSubExpressionContainerVariable(newId[0]),//Makes the container's html
droppedOnParent = droppedOn.parent();
droppedOnParent.append(subExpressionContainer);//Append the container to the DOM
let droppedOnSubRuleContainer = $(`#subRuleBoxContainer-${newId[0]}`);
$(dropped).detach().css({ top: 0, left: 0 }).appendTo(droppedOnSubRuleContainer);
$(droppedOn).detach().css({ top: 0, left: 0 }).appendTo(droppedOnSubRuleContainer);
},
greedy: true
});
And here it is the container's droppable code :
function SetDropZoneEvent() {
$('.dropZone').droppable({
tolerance: 'pointer',
accept: '.ruleBox,.subExpressionContainer',
drop: function (event, ui) {
let dropped = ui.draggable,
droppedOn = $(this),
droppedParent = dropped.parent();
$(dropped).detach().css({ top: 0, left: 0 }).appendTo(droppedOn);
},
greedy: true
});
The code of the container maker :
function MakeSubExpressionContainerVariable(id) {
return `
<div class="subExpressionContainer" id="subExpressionContainer-${id}">
<button class="searchButtons" id="addEditButt" onclick="ToggleOperator(this)"
value="AND" >AND</button>
<div class="subRuleBoxFreeSpace">
</div>
<div class="subRuleBoxContainer dropZone" id="subRuleBoxContainer-${id}">
</div>
<button class="searchButtons" id="addEditButt"
onclick="RemoveSubExpressionContainer('subExpressionContainer-${id}')"
value="X" >X</button>
</div>`}
The code of rule box maker :
function MakeRuleBoxVariable(sPName, sPDName, sPType, sPRelation, sPDetailAction,
sCondition, sContent) {
let id = new Date().getTime();
return `
<div class="ruleBox" id="ruleBox-${id}" data-property-name = "${sPName}"
data-type = "${sPType}" data-relation = "${sPRelation}" data-detail-action =
"${sPDetailAction}" >
<div class="rule">
<div class="ruleText"><span style="height: 100%;">"${sPDName}"
"${sCondition}" "${sContent}"</span></div>
</div>
<div class="searchBoxButt">
<div class="searchBoxRemoveIcon"><span> </span><a
onclick="RemoveRuleBox('ruleBox-${id}')"><i class="fa fa-times">
</i></a><span> </span>
</div>
<div class="searchBoxEditIcon"><span> </span><i class="fa fa-edit"></i><span> </span>
</div>
</div>
</div>`
}
I have a system of jQuery dropdown menus, but have a strange problem where the text cannot be selected (e.g. to copy/paste) after the menu is used.
Check out the Fiddle here, and try selecting the sample text before using the menu. Then hover over a menu item, and the text can no longer be selected.
I need the text to still be selectable after the user opens/closes the menus. Take a look:
HTML Structure:
<div class="oe_wrapper">
<div id="oe_overlay" class="oe_overlay"></div>
<ul id="oe_menu" class="oe_menu">
<li>Home
<div class="hover-div">Content 1</div>
</li>
<li>Projects
<div class="hover-div">Content 2</div>
</li>
<li>No Hover
<div class="hover-div not-shown">This should not appear and no other menu divs or the dark overlay should be shown.</div>
</li>
<li>Events
<div class="hover-div">Content 4</div>
</li>
<li>Stores
<div class="hover-div">Content 5</div>
</li>
</ul>
JS:
$(function () {
var $oe_menu = $('#oe_menu');
var $oe_menu_items = $oe_menu.children('li');
var $oe_overlay = $('#oe_overlay');
$oe_menu_items.bind('mouseenter', function () {
var $this = $(this);
$this.addClass('slided selected');
if ($this.children('.hover-div').hasClass('not-shown')) {
$oe_menu_items.not('.slided').children('.hover-div').hide();
$this.removeClass('slided');
} else {
$this.children('.hover-div').css('z-index', '9999').stop(true, true).slideDown(200, function () {
$oe_menu_items.not('.slided').children('.hover-div').hide();
$this.removeClass('slided');
});
}
}).bind('mouseleave', function () {
var $this = $(this);
$this.removeClass('selected').children('.hover-div').css('z-index', '1');
});
$oe_menu.bind('mouseenter', function () {
var $this = $(this);
$oe_overlay.stop(true, true).fadeTo(200, 0.6);
$this.addClass('hovered');
}).bind('mouseleave', function () {
var $this = $(this);
$this.removeClass('hovered');
$oe_overlay.stop(true, true).fadeTo(200, 0);
$oe_menu_items.children('.hover-div').hide();
})
});
Thanks in advance for your help. Once again, this is the Fiddle.
The problem is your div oe_overlay is starting out display:none (good), then fading in on mouse over, then fading out on mouse out, but it's not being set to display:none again so it's effectively masking all other input on the page.
All you need is to hide the div after you've faded it out:
$oe_overlay.stop(true, true).fadeTo(200, 0, function() {
$(this).hide();
});
See updated fiddle
I am using jquery ui sortable with connected lists. I have 2 problems with one most important requirement.
Items goes behind the other list while dragging li.ui-splitselect-item
Dragging item to right(when mouse is too right) creates Horizontal scroll
IMPORTANT: Lists ul.ui-splitselect-list should have overflow-y:auto; So Header of lists stay fixed
and only list items are scrolled
NOTE:
I previous asked this question on STACKOVERFLOW but didnt notice my important requirement was missing from solution so i opened question again with clarity.
JSFIDDLE: http://jsfiddle.net/bababalcksheep/z67Td/
HTML Mockup:
<div class="ui-splitselect ui-helper-clearfix ui-widget ui-widget-content" style="height:200px;" >
<div class="ui-widget-content ui-splitselect-selected">
<div class="ui-widget-header ui-helper-clearfix">
List1
</div>
<ul id="sortable1" class="ui-splitselect-list" style="height: 332px;">
<li class="ui-splitselect-item ui-state-default">
<a class='ui-splitselect-handle-drag'><span class='ui-icon ui-icon-carat-2-n-s'></span></a>
<span class="ui-splitselect-handle-select">TEST-List1</span>
<a class="ui-splitselect-handle-move" href="#"><span class="ui-icon ui-icon-plus"></span></a>
</li>
</ul>
</div>
<div class="ui-widget-content ui-splitselect-available" >
<div class="ui-widget-header ui-helper-clearfix">
List2
</div>
<ul id="sortable2" class="ui-splitselect-list" style="height: 332px;">
</ul>
</div>
</div>
CSS:
.ui-splitselect{font-size:.8em;width:100%!important;text-align:center;margin:0 auto;padding:0}
.ui-splitselect ul{-moz-user-select:none}
.ui-splitselect .ui-widget-header{border:none;font-size:11px}
.ui-splitselect-selected{height:100%!important;float:left;border:none;width:50%;margin:0;padding:0}
.ui-splitselect-available{height:100%!important;width:49.4%;float:left;border-top:none;border-bottom:none;border-right:none;margin:0;padding:0}
.ui-splitselect-list{height:92%!important;position:relative;list-style:none;overflow:auto;margin:0;padding:0}
.ui-splitselect-item{cursor:default;line-height:20px;height:20px;font-size:11px;list-style:none;display:list-item;white-space:nowrap;overflow:hidden;margin:1px;padding:0}
.ui-splitselect-item.ui-sortable-helper{z-index:99999}
.ui-splitselect-handle-select{float:left}
.ui-splitselect-handle-drag{float:left;height:20px;border-top:0;border-bottom:0;cursor:pointer;margin:0 10px 0 5px;padding:2px 5px}
.ui-splitselect-handle-move{text-decoration:none;cursor:pointer;float:right;height:20px;border-top:0;border-bottom:0;margin:0 5px 0 10px;padding:2px 5px}
JS:
$("#sortable1, #sortable2").sortable({
connectWith: ".ui-splitselect-list",
containment: ".ui-splitselect",
scroll: false,
placeholder: "ui-state-highlight ui-splitselect-item"
}).disableSelection();
Try adding appendTo: document.body and helper: clone options for sortable, like this:
$("#sortable1, #sortable2").sortable({
appendTo: document.body,
helper: "clone",
connectWith: ".ui-splitselect-list",
containment: ".ui-splitselect",
scroll: false,
placeholder: "ui-state-highlight ui-splitselect-item"
}).disableSelection();
Js fiddle: http://jsfiddle.net/XpP25/2/
Trick is in creating sorting helper that clones your original element, and then appending it to body element to resolve zIndex issues. All helpers are automatically removed after stop event of draggable and sortable, so it shouldn't mess your code :)
Hope it helps.
I was having a similar issue with nested sortable items. I have multiple sortable containers, that make up a grid, then widgets inside of those sortable containers. Inside of each widget there is a nested sortable container which takes up the width and height. Inside of the nested sortables I can have multiple nested-widgets, spanning the width of the nested sortable.
Here is how one of those sortables would look:
<div class="sortable">
<div class="widget">
<div class="nested-sortable">
<div class="nested-widget"></div>
</div>
</div>
</div>
Now, once I started dragging my nested sortable item, it would go behind every outer widget except for the one containing it. I tried changing the z-index of the items on sort start and no luck. I needed something like jQuery UI's Draggable stack option, which "stacks" the currently dragged item over all other items of the same class.
Here is jQuery UI's draggable stack function on github at line 800.
So, my friend and I modified that code a bit, and called it on the "outer" widget.
$.fn.stack = function () {
// where $(this) == '.widget'
var o = $(this).closest('.sortable').siblings('.sortable').find('.widget');
// create an array of all the widgets
var group = $(o).sort(function(a,b) {
// compare the each set of widgets
return (parseInt($(a).css("z-index"),10) || 1) - (parseInt($(b).css("z-index"),10) || 1);
});
if (!group.length) { return; }
var min = parseInt($(group[0]).css('z-index')) || 1; // first widget's z-index
$(group).each(function(i) {
// increase each widget's z-index by min + $(this) widget's index value
$(this).css('z-index', min + i);
});
// make currently dragged widget's z-index min + length of group
$(this[0]).css('z-index', min + group.length);
}
Then call in sortable start:
$('.nested-sortable').sortable({
start: function(event, ui) {
$(this).closest('.widget').stack();
}
});
Here is my codepen for reference: Nested Grid System
I have a sortable element of div
<div class="question-constructor multiple-choice-problem">
<label for="textbox" class="question-label"> #. Edit this to define question: </label>
<input type="radio" name="test" id="option-1-1" class="question-radio" style="float:left;">
<input type="radio" name="test" id="option-1-2" class="question-radio" style="float:left;">
<input type="radio" name="test" id="option-1-3" class="question-radio" style="float:left;">
<input type="radio" name="test" id="option-1-4" class="question-radio" style="float:left;">
</div>
This divs are draggable then are dropped to the sortable. Here is the div where they drop the draggable:
<div id="preview" ></div>
Here is my sortable JS:
var sortableIn = 0;
$('#preview').sortable({
receive: function(event, ui) {
sortableIn = 1;
$(ui.item).addClass('editable');
},
placeholder: 'ph',
over: function(event, ui) { sortableIn = 1; },
out: function(event, ui) { sortableIn = 0; },
start: function( event, ui ) {
$(ui.helper).addClass('on-sort');
},
beforeStop: function (event, ui) {
if (sortableIn == 0) {
ui.item.remove();
}
},
stop: function( event, ui ) {
$(this).find('.on-sort').removeClass("on-sort");
}
});
What I want to do is create an onclick even to the sortable items specificaly. I tried using this:
$(function() {
$(document).on('click', '#preview ', function() {
console.log('clickable');
});
});
But when I clicked the sortable items It clicks every thing. I want to change the text of the label on the sortable div where I specifically clicked.
For example:
I dragged .question-constructor div 3 times to the #preview div. (This will make the #preview sortable div have 3 items)
When I click the 2nd item in the sortable div, I want to change the text label on it to another value( only on this item ).
How can I do this?
If my question is unclear please comment below and I will respond accordingly.
You could still use the on click event but over the clicked item:
$(".question-label").on("click", function (e) {
$(e.target).text('I am changed');
});
Fiddle: http://jsfiddle.net/eBXkT/
I'm working with Jquery UI draggable and droppable.
I have a container that accepts all the divs of the .category1 class, and what I have to do is:
If I put a div into the container that already has another div, revert the old div back to the
original position.
This is the code I have:
$(document).ready(function () {
$(function () {
$("#Part1").draggable({ revert: "invalid", snap: "#Part1Container", snapMode: "inner"
});
$("#Part1Container").droppable({
accept: ".category1",
drop: function (event, ui) {
//Some other logic
}
}
});
And the Html
<div id="Part1" class="ui-widget-content category1"></div>
<div id="Part2" class="ui-widget-content category1"></div>
I want the Part1 to be back to the original position if I insert Part2 in the container, and viceversa. And this has to work for n divs of the same class.
Any suggestions?
Tnx in advance :)
I solved it by assigning it a class when it goes into the container the first time, and then delete it when moving another div
$(".inCategory2").animate({
top: 0,
left: 0
}).removeClass("inCategory2");
ui.draggable.addClass("inCategory2");