jQueryUI: how to restrict droppable area to multiple divs? - javascript

It feels like the question is already answered:
How to select multiple areas in containment using jQuery UI draggable
Set more than one containment in jQuery Draggable
I have 3 timelines and some draggable elements to place there. For some reason I cannot get it to work. This is the syntax I'm using: containment: ".timeline1, .timeline2, .timeline3"
$(function() {
$(".timeline1, .timeline2, .timeline3").droppable();
$(".event").draggable({
containment: ".timeline1, .timeline2, .timeline3"
});
});
.timeline1, .timeline2, .timeline3 {
width: 500px;
height: 40px;
border: 3px dashed gray;
margin-bottom: 10px;
}
.event {
height: 40px;
background: gray;
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css" />
<div class="timeline1"></div>
<div class="timeline2"></div>
<div class="timeline3"></div>
<div class="event">dance</div>
<div class="event">sleep</div>
<div class="event">eat</div>
Update found in the docs: http://api.jqueryui.com/draggable/#option-containment
The draggable element will be contained to the bounding box of the first element found by the selector
Question is still valid, I'd really like to know how to restrict droppable area to multiple divs?

I'm not sure if you can do this with the containment option, but you can use snap, snapMode and revert to accomplish what you're trying to do.
I'd add a common class like timeline-droppable to your timeline elements to make it easier:
<div class="timeline1 timeline-droppable"></div>
<div class="timeline2 timeline-droppable"></div>
<div class="timeline3 timeline-droppable"></div>
Use the snap option to snap to your droppable timelines. Use the revert option to determine whether the draggable was dropped in a valid droppable:
$(function() {
$(".timeline-droppable").droppable();
$(".event").draggable({
snap: ".timeline-droppable",
snapMode: "inner",
revert: function(droppedElement) {
var validDrop = droppedElement && droppedElement.hasClass("timeline-droppable");
return !validDrop;
}
});
});
Of course you'll need to tweak the CSS to make your event elements fit nicely inside your timeline elements.

Related

How can I let people drag and drop LI's to a specific place in a list? (console.log issues)

I'm facing two issues, one of which is a goal and one of which is failure to obtain information from console.log() calls.
Let's look at the goal first:
I have a JSfiddle at https://jsfiddle.net/L7sbhzzj/ for a project I'm working on. The code I'm working on is:
jQuery('.collection').droppable(
{
'accept': '.collection > li',
'drop': function(e, ui)
{
console.log('Reached here!');
console.log(this);
jQuery('#selection').append(ui.draggable);
}
});
Essentially, I want people to be able to drag and drop elements to a specific position on a list. So, in the JSfiddle, you can drag "Fiction" to the right, but if you do that and then drag over "Nonfiction", "Nonfiction" is only added to the end; you cannot subsequently drag "Nonfiction" to be above and before "Fiction".
I'd like to avoid reinventing the wheel on this; I imagine there is some standard pattern like "Put the LI being dropped immediately before the target UL's LI that has the lowest distance to the top of the page but is still equal or greater than the dropped LI's distance to the top of the page."
Now to return to the other issue I'm facing: either jQuery('#selection').append(ui.draggable); is working or something else is doing equivalent work, but none of my console.log()s seem to be reported.
I have some ideas for how to implement something, but it would be nice to introspect and obtain console.log()s' diagnostic output while I'm working on things.
Is the 'drop' taking effect at all? Is it working some other way? How can I get things like what element the object was dropped to?
--EDIT--
I realized that I'd asked for one side of what I want to. I'd like people to be able to take item XYZ from one container to another and then back if they change their mind. Snowmonkey's solution worked beautifully for the right list being sortable. However, the following adaptation failed, perhaps because I called two incompatible enhancements:
jQuery(function()
{
jQuery('#selection').sortable(
{
});
jQuery('li', jQuery('#source')).draggable(
{
'connectToSortable': '#selection',
'cancel': 'a.ui-icon',
'revert': 'invalid',
'containment': 'document',
'cursor': 'move'
});
jQuery('#source').sortable(
{
});
jQuery('li', jQuery('#selection')).draggable(
{
'connectToSortable': '#selection',
'cancel': 'a.ui-icon',
'revert': 'invalid',
'containment': 'document',
'cursor': 'move'
});
How can I get a fully two-sided variation of Snowmonkey's answer?
Thanks,
So you want to connect a draggable to a sortable? Here's a simple way. Get rid of the droppable altogether, and simply add the 'connectToSortable' rule to your draggable. Thus, #selection remains a sortable and #source remains a draggable, that can drop into any position on #source.
jQuery(function() {
$(".collection").sortable({
});
jQuery('li', jQuery('.collection')).draggable({
'connectToSortable': '.collection',
'cancel': 'a.ui-icon',
'revert': 'invalid',
'containment': 'document',
'cursor': 'move'
});
});
body {
background-color: #ccc;
font-family: Verdana, Georgia;
}
div.main {
margin-left: auto;
margin-right: auto;
width: 440px;
}
div.table {
display: table;
width: 440px;
}
div.td {
display: table-cell;
width: 50%;
}
div.tr {
display: table-row;
}
ul.collection {
background-color: white;
list-style: none;
padding-left: 0;
min-height: 100px;
padding-left: 0;
width: 200px;
}
ul.collection > li {}
ul#selection {
float: right;
}
ul#source {
float: left;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div class="main">
<div class="table">
<div class="tr">
<div class="td">
<ul id="source" class="collection">
<li>Everything</li>
<li>Nonfiction</li>
<li>Fiction</li>
<li>Poetry</li>
</ul>
</div>
<div class="td">
<ul id="selection" class="collection">
<li>Empty</li>
</ul>
</div>
</div>
</div>
</div>
So i updated the above post to make it work in both directions. Rather than using the ID for the two elements, I used the class that they have in common. Both .collection elements are sortable, and both connectToSortable .collection elements. Hope it helps!
You can achieve what you want just using jquery ui sortable. If you want to be notified whenever an item added to selection, you can listen for receive event.
jQuery(function()
{
jQuery( "#source" ).sortable({
connectWith: "#selection",
}).disableSelection();
jQuery("#selection").sortable({
receive: function() {
console.log("changed");
}
})
});

How can i find element which is below to the another element?

I am trying to drag and sort images using jquery UI. I have cloned element which is I am trying to drag. I need to show a line between two images based on cloned image position. How can I achieve this? Thanks in advance.
Here is the one example.
http://jsbin.com/owuxek/9/edit?html,js,output
I am showing images instead of "Item A Item B.." Now I need to show a line between two li's while one 'li' is moving.
EDIT: That is, when I click "and pick" an image and hover it onto the list of images already in place, I wish to show a 'separator line' between the images over which I am currently hovering, so as to indicate to the user where the image would be placed if user releases the mouse click.
In the attached JSbin code, when I move an element from the list above and try to move it into the list below, a small white separating space appears between the elements of the list below, over which the mouse hovers. I need to replicate this effect for the below element layout.
<div id="single_album_grid" class="sortable">
<div id="divId1">
<img class="assetImg" id="imageId1" src="url">
</div>
<div id="divId2">
<img class="assetImg" id="imageId2" src="url">
</div>
<div id="divId3">
<img class="assetImg" id="imageId3" src="url">
</div>
</div>
This is my updated code:
$( "#divId1" ).draggable({
containment: $('#single_album_grid'),
helper: 'clone'
});
$( "#divId1" ).droppable({
drop: function(event, ui) {
}
});
If you use jquery UI sortable widget, it automatically inserts a placeholder element to at the target position.
You can style it like a line or whatever else you want with .ui-sortable-placeholder selector via css.
$(function() {
$("#single_album_grid").sortable()
});
div div {
height: 50px;
background: dodgerblue;
border: 2px solid white;
}
.ui-sortable-placeholder {
visibility: visible !important;
height: 5px;
background: hotpink;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div id="single_album_grid" class="sortable">
<div id="divId1">
<!--img class="assetImg" id="imageId1" src="url"-->
</div>
<div id="divId2">
<!--img class="assetImg" id="imageId2" src="url"-->
</div>
<div id="divId3">
<!--img class="assetImg" id="imageId3" src="url"-->
</div>
</div>
over: function (event, ui) {
//code here
}
out: function (event, ui) {
//code here
}
worked for me!!

How can I make the parent div draggable

I have a div containing three buttons. The div needs to be draggable, so that you can drag all three buttons around the screen together. That works fine, but the problem is that when I click on of the individual buttons it inherits the draggable id and it is draggable on it's own. I do not want that to happen. So my question is: how do I make my buttons draggable, but make them always stay together and keep them clickable. I added the code below, but here is a JSFiddle: http://jsfiddle.net/2ga50vvt/
So to be clear: the div also needs to be draggable through dragging one of the individual buttons, but then the rest of the div needs to stick with it. Now dragging an individual button only moves the button.
P.S. I do not want to use JQuery UI
HTML:
<div id="draggable" class="ui-widget-content">
<button ng-click="menu.shown = !menu.shown">MENU</button>
<br>
<button ng-click="disconnect()">CLOSE</button>
<br>
<button ng-click="">KEYS</button>
</div>
JS
$(document).ready(function() {
var $dragging = null;
$('body').on("mousedown", "#draggable", function(e) {
$(this).attr('unselectable', 'on').addClass('dragged');
var el_w = $('.dragged').outerWidth(),
el_h = $('.dragged').outerHeight();
$('body').on("mousemove", function(e) {
if ($dragging) {
$dragging.offset({
top: e.pageY - el_h / 2,
left: e.pageX - el_w / 2
});
}
});
$dragging = $(e.target);
}).on("mouseup", ".dragged", function(e) {
$dragging = null;
$(this).removeAttr('unselectable').removeClass('dragged');
});
});
CSS:
body {
padding: 50px;
}
.dragged {
background-color: yellow;
}
#draggable {
position: fixed;
width: 150px;
height 150px;
padding: 0.5em;
background: red;
background-color: black;
z-index: 1000;
cursor: move;
float: left;
}
Update 1
This is a working solution: http://jsfiddle.net/2ga50vvt/3/
However when I click on the div and start dragging the center of the div jumps to my cursor. It works great, but it looks a bit wonky. Is there a way to prevent the div from moving to my cursor?
Your help is most welcome.
You can read the target property of the event and return false to avoid all not #draggable to be draggable.
if(e.target.id !== "draggable") {
return false;
}
The edited fiddle:
http://jsfiddle.net/2ga50vvt/1/
It works perfectly, but one suggestion: don't target with ids because with this code you can't drag more of one element (ids must be unique), so the workaround is to write an attribute or a classname and play with it.
Good luck.
Use $dragging = $('#draggable'); instead of $dragging = $('e.target');
It will drag div if you try to drag using cursor on button. It will drag #draggable instead of target.
Working Fiddle
Presuming you're opposed to JQueryUI for it's file size, I'd still recommend a prebuilt solution because why reinvent the wheel?
Draggabilly is a really nifty library that I've used when resource size has been an issue. It's 20k minified (obviously even smaller gzipped) and available on a CDN - which in itself has lots of benefits e.g. caching.
$(function() {
$( "#draggable" ).draggabilly();
});
There's a few CSS hooks, different options, events etc.
JSFiddle here

How to change image side of cursor on drag event using JQuery

When you drag an file on browser screen, an image appear side of mouse cursor that is windows default image. This images is various like Copy, Move and Forbide. See its at bottom.
How can i change image side of mouse cursor to this images using javascript or JQuery? For example when i drag a file and move mouse in undragable area, forbiden image display side of cursor.
You can use the dataTransfer.dropEffect property of the dragover event to set the small image besides the cursor:
$(".targetDiv").on("dragover", function (event) {
event.preventDefault();
event.originalEvent.dataTransfer.dropEffect = "none"; // Shows the "forbidden" image
});
The values for that property are copy, move, link and none. You can test these values in the code snippet below. Please note that the originalEvent must be used. According to my tests, it works in Firefox and Chrome but not in IE.
$(function () {
$(".targetDiv").on("dragover", function (event) {
event.preventDefault();
event.originalEvent.dataTransfer.dropEffect = event.target.getAttribute("data-effect");
});
});
.targetDiv
{
display: inline-block;
border: solid 1px black;
width: 80px;
height: 50px;
margin: 4px;
text-align: center;
line-height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Drag a file over each block </p>
<div>
<div data-effect="link" class="targetDiv">Link</div>
<div data-effect="move" class="targetDiv">Move</div>
</div>
<div>
<div data-effect="copy" class="targetDiv">Copy</div>
<div data-effect="none" class="targetDiv">None</div>
</div>
You can change the cursor image by changing the property of the cursor by css using jquery.
function ondrag(event) {
$('body').css('cursor', 'wait');
}
You can check the various cursor property here.
http://www.w3schools.com/cssref/pr_class_cursor.asp
If you want to replace the cursor with a custom image you can use this:
https://github.com/Webbrother/jquery.change-cursor
If you want to limit draggables to a certain area,
Try using "containment" option:
http://docs.jquery.com/UI/Draggable#option-containment
You can do it with jquery draggable
Here is the preview what i have done
$( ".your_image" ).draggable({
drag: function() {
$(".your_image").css("cursor","url(https://cdn1.iconfinder.com/data/icons/CrystalClear/16x16/actions/move.png), auto");
},
stop: function() {
$(".your_image").css("cursor","url(https://cdn4.iconfinder.com/data/icons/32x32-free-design-icons/32/Copy.png), auto");
}
});
.your_image{
height:100px;
width:100px;
background-color:red;
cursor:url(https://cdn4.iconfinder.com/data/icons/32x32-free-design-icons/32/Copy.png), auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div>
<div class="your_image">
</div>
</div>
<div class="log">
</div>

newly created dom elements cannot be draggable

I'm using jquery and jquery ui to create draggable elements.
i created a small jsfiddle example at https://jsfiddle.net/2j2c8vLc/
that demonstrates what i'm trying to do.
javascript code:
$(function(){
$('body').append('<div id="moshe">hi</div>');
$('#moshe').draggable();
});
in the example i add to the body a div element after document ready event and then trying to make it draggable. the results are that it's not draggable, the classes are added to the element but it seems that it's not enough.
any ideas?
update
more info to clear things up.. i'm trying to move a readonly text input.
i created new jsfiddle at http://jsfiddle.net/70f3dbLh/2/
with the following javascript code:
$(document).ready(function(){
$("<div>").attr("id", "moshe").html("<input readonly type=\"text\"></input>").appendTo("body").draggable();
});
as you can see here.. the text input inside the div is not draggable
i tried to create another example of trying to create a text input without a div and make it draggable.. same results. it's not draggable.
jsfiddle at http://jsfiddle.net/70f3dbLh/3/
javascript code:
$(document).ready(function(){
$("<input readonly value=\"aaa\" type=\"text\"></input>").attr("id", "moshe").appendTo("body").draggable();
});
Use following jsfiddle: http://jsfiddle.net/70f3dbLh/1/ and look at this: http://jsfiddle.net/70f3dbLh/1/show/
The code is something like
$(document).ready(function(){
$("<div>").attr("id", "moshe").html("hi").appendTo("body").draggable();
});
It is then draggable.
Update on your update
I updated my post, because you updated your post.
I added a new jsfiddle. http://jsfiddle.net/8scyhq01/2/ In general, Input Fields are not draggable, but if you put a layer above the input field, this layer then is draggable. And the Input Field will be dragged too.
$("<div>").addClass("layer").attr("id", "moshe").html("<div class=\"layer\"></div><input readonly type=\"text\"></input>").appendTo("body").draggable();
I have modified
a code I found, From this post to make text input draggable, putting a div on top of it.
$(function() {
$( "#resizable" ).resizable({
containment: "#container"
});
$( "#draggable" ).draggable({containment: "#container"});
});
#container { width: 300px; height: 300px; }
#container h3 { text-align: center; margin: 0; margin-bottom: 10px; }
#resizable, #container { padding: 0.5em; }
#d{
background:blue;
width:100px;
height:30px;
position:relative;
top: 2em;
left:0em;
z-index:9;
opacity:0.1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="container" class="ui-widget-content">
<h3 class="ui-widget-header">Containment</h3>
<span id="draggable"><div id='d'></div>
<input type="text "id="resizable" class="ui-state-active" readonly value="This is input box">
</span>
</div>

Categories