jQuery draggable position unchanged - javascript

I have four draggables next to each other and I want it to be so that once a draggable is remove from the list, the rest would stay in place.
<div class="draggables">
<div id="d1" class="box">
first box</div>
<div id="d2" class="box">
second box</div>
<div id="d3" class="box">
third box</div>
<div id="d4" class="box">
forth box</div>
</div>
CSS
.draggables{
width: inherit;
height: 60px;
margin-left: 20px;
}
.box{
width: 180px;
height: 30px;
float:left;
margin-left: 20px;
}
jQuery:
$("#d1, #d2, #d3, #d4").draggable({
revert: function (event, ui) {
$(this).data("uiDraggable").originalPosition = {
top : 0,
left : 0,
};
return !event;
}
});

You could set the opacity of the "removed" item to 0 to simulate hiding.
Instead of using the revert option, you can use stop to trigger an action when the mouse is released. Also, you don't need to invoke draggable using each individual id. You can simply call it on .box since all of the divs share that class.
In the example below, I'm assigning a class of hidden, which sets the opacity of the chosen div/element to 0.
JQuery:
$(".box").draggable({
stop: function(event, ui) {
$(this).addClass('hidden');
}
});
CSS:
.hidden {
opacity: 0;
}
Fiddle Example

Related

Lower the margin by time when using slideToggle in Jquery

I have this example
$(document).ready(function() {
$("#btn").click(function() {
removeSecondContainer();
});
});
function removeSecondContainer() {
var container = $("#c2");
container.slideToggle(500, function() {
container.remove();
});
}
.container {
margin: 20px auto;
height: 20px;
width: 100px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Remove the second container</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>
As you can see, the process is not smooth at all. When the second container gets removed, the margin of the second container gets removed too. This causes a pull from the top.
How can I get this smoothly? I thought about lowering the margin by time to 0 when removing the container.
You are facing a margin collapsing issue. As you may notice you don't have 40px between each container like expected but only 20px.
As you can read here:
In CSS, the adjoining margins of two or more boxes (which might or
might not be siblings) can combine to form a single margin. Margins
that combine this way are said to collapse, and the resulting combined
margin is called a collapsed margin.
So when removing the element you decrease both margin at the top and bottom to leave the maring of the first and last element. And when the height of the element reaches 0 and get removed, you create another margin collapsing between the remaining block and thus the jump from 40px to 20px of margin.
And idea to avoid this is to increase height and use linear-gradient to color only the part you want (and leave transparent the part previously used for the margin). Like that the transition will go smoothly as there is no more margin issue.
$(document).ready(function() {
$("#btn").click(function() {
removeSecondContainer();
});
});
function removeSecondContainer() {
var container = $("#c2");
container.slideToggle(500, function() {
container.remove();
});
}
.container {
margin: auto;
height: 60px;
width: 100px;
background: linear-gradient(to bottom, transparent 33.33%, red 33.33%, red 66.67%, transparent 66.67%);/
box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Remove the second container</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>
Or use flex by adding another container as there is no margin collpasing with flexbox (Margin collapsing in flexbox):
$(document).ready(function() {
$("#btn").click(function() {
removeSecondContainer();
});
});
function removeSecondContainer() {
var container = $("#c2");
container.slideToggle(500, function() {
container.remove();
});
}
.box {
display: flex;
flex-direction: column;
}
.container {
margin: 20px auto;
height: 20px;
width: 100px;
background: red;
box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Remove the second container</button>
<div class="box">
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>
</div>
Its due to clearing. The bottom margin is not working well with them. Either use float or remove margin-bottom or margin-top to 0
here is Example
edit: update with remove div
https://jsfiddle.net/f5zw18er/3/
You could potentially use jQuery animate with a callback function. It's slightly different because it doesn't include the slide toggle, but in your example it's only being removed, so this could work.
Here we're removing the margin and also hiding the element with the animation, and then finally removing the element in the callback.
$(document).ready(function() {
$("#btn").click(function() {
removeSecondContainer();
});
});
function removeSecondContainer() {
var container = $("#c2");
container.animate({ 'margin' : '-20px auto', 'opacity': 0 }, 500, function(){
container.remove();
});
}
.container {
margin: 20px auto;
height: 20px;
width: 100px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Remove the second container</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>

How can I save dragged & dropped elements VALUE after dropped all players (soccer manager)

i have a player soccer field and i want the user to create his own LineUp via Drag and Drop...
have a look at my fiddle: https://jsfiddle.net/ahsce0oj/2/
this is my js code and my fiddle:
$(function() {
$("#draggable2").draggable({
appendTo: "body",
cursorAt: {
cursor: "move",
top: 5,
left: 0
},
helper: function(event) {
return $("<img width='5%' src='https://d34h6ikdffho99.cloudfront.net/uploads/real_team/shirt/1174/shirt-300.svg'>");
}
});
$("#droppable2").droppable({
accept: "#draggable2",
classes: {
"ui-droppable-active": "ui-state-default"
},
drop: function(event, ui) {
$(this).find("p").html("<img width='100%' src='https://d34h6ikdffho99.cloudfront.net/uploads/real_team/shirt/1174/shirt-300.svg'>");
}
});
});
(there is only one position at the moment, just a test)
----> You have to move the Text (right side) into the rectangle (mean position of my goalkeeper)
but when i have my eleven positions and the "user" is done with his line up draft, how can I save his selection?
with IDs? or every time directly after he dropped an element?
thanks for any hints
Edit: I would be really happy for any other hints how could I delete a dropped player (--> manipulate the DOM—for example delete his shirt and write "GOALKEPPER" instead into a DIV or a <p> Element)
There's a lot of ways to accomplish your goals (pun intended, ha!) here. I will what I would do:
Working Example: https://jsfiddle.net/Twisty/54vgb8bx/4/
HTML Snippet
<section id="content">
<div id="field">
<div id="goalie" class="drop center rear">
<p>Goal Keep</p>
</div>
<div id="rightback" class="drop right mid">
<p>R. Back</p>
</div>
<div id="leftback" class="drop center mid">
<p>C. Back</p>
</div>
<div id="leftback" class="drop left mid">
<p>L. Back</p>
</div>
<div id="rightforward" class="drop right for">
<p>R. Forward</p>
</div>
<div id="leftforward" class="drop left for">
<p>L. Forward</p>
</div>
</div>
</section>
<!-- SIDBAR RIGHT -->
<aside>
<div id="item-1" data-type="shirt" class="drag">
<p>Move me into the rectangle! ! !</p>
</div>
</aside>
CSS Snippet
.drag {
float: left;
padding: 0% 1% 0%;
margin-top: 1%;
margin-right: 0%;
width: 39%;
color: white;
background-color: black;
}
.drop {
border: 2px solid white;
height: 5vw;
width: 5vw;
color: white;
font-size: 13px;
text-align: center;
}
.rear {
position: absolute;
top: 0;
}
.mid {
position: absolute;
top: 150px;
}
.for {
position: absolute;
top: 300px;
}
.right {
left: 135px;
}
.center {
left: 273px;
}
.left {
left: 403px;
}
#field span.remove:hover {
background-color: #000;
border-radius: 8px;
}
jQuery
$(function() {
$(".drag").draggable({
appendTo: "body",
cursorAt: {
cursor: "move",
top: 5,
left: 0
},
helper: function() {
var displayImage = $("<img>", {
width: "5%",
src: 'https://d34h6ikdffho99.cloudfront.net/uploads/real_team/shirt/1174/shirt-300.svg'
}).data("type", $(this).data("type"));
return displayImage;
}
});
$(".drop").droppable({
accept: ".drag",
classes: {
"ui-droppable-active": "ui-state-default"
},
drop: function(event, ui) {
var removeButton = $("<span>", {
class: "ui-icon ui-icon-circle-close remove"
});
var dropImage = $("<img>", {
width: "100%",
src: ui.helper.attr("src")
});
$(this)
.data("type", ui.helper.data("type"))
.data("title", $(this).text())
.find("p")
.html(dropImage);
removeButton.appendTo($(this).find("p")).position({
my: "left bottom",
at: "right top",
of: $(this).find("img")
});
}
});
$("#field").on("click", "span.remove", function() {
var me = $(this).parent(); // p
var parent = me.parent(); // div
var title = parent.data("title");
parent.data("type", "").html("<p>" + title + "</p>");
});
});
First you will see I adjusted the id and class attributes. This allows the drag and drop elements to have much more specific IDs, and then can be styled via CSS in a more generalized manner. I also added more positions to flush out the example of how this can help when initializing the Draggable and Droppable portion.
Second, you may notice I added a data-type attribute to our drag item. This can be a SKU or ID from a database, name of a product, whatever. We can also change the attribute to fit the data better. But this will be how we identify what the user has selected and what that have dropped it on later.
Next, we update the CSS to work the way we might need. Making use of position, I can make the #field our boundary, so that each absolute element within is positioned exactly where it should be.
Lastly, a lot of jQuery code. Not a lot of big changes to our draggables. Consider now that if you have more items, this will apply to each of them based on their class selector. When we make the helper, we tack on the data attribute so that we can tact it to the drop position.
For the drop, we want to do more.
Accept only a drag item
Append in the img
Update the product / ID data
Create a way for user to remove selection
Store the original text if item is removed
It was not clear if this should no longer be droppable, but you could easily add that in, such that you could not drop a new item onto it. But then initial drop again in the remove button.
All this happens in the drop. To avoid confusion (around $(this)), I setup the remove button click function outside of the drop.
This should be enough to get you well along. I suspect you'll make a save or complete button. In this I would advise iterating over each .drop and look for info in the data-type attribute for each as well as the id from the parent div. You can then build an object or array to send the data along to be processed.

Mouseenter mark only one active node in hierarchy

I have several nested div-s and I would like to mark only one of them active when the mouse is over that element. The following code isn't work for every situation.
Code sample:
Red -> container
Green -> outer
Yellow -> inner
Blue ->active
The most inner div with the mouse should have the blue background only.
It works only for very few interactions and most of the times it fails. What would be the best and less resource heavy solution for this problem?
function markActive($el) {
$el.addClass('active');
$el.parent().triggerHandler('inactive');
}
function markInActive($el) {
$el.removeClass('active');
$el.parent().triggerHandler('active');
}
$('div').on({
mouseenter: function() {
markActive($(this));
},
mouseleave: function() {
markInActive($(this));
},
inactive: function() {
markInActive($(this));
},
active: function() {
markActive($(this));
}
});
div {
clear: left;
float: left;
padding-left:20px;
height: 400px;
background: #f00;
}
div div {
height: 125px;
background: #0f0;
}
div div div {
width: 280px;
height: 50px;
background: #ff0;
}
div.active {
background: #00f;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="container">
<div class="outer">
<div class="inner">
<span>Most inner #1</span>
</div>
<div class="inner">
<span>Most inner #2</span>
</div>
</div>
<div class="outer">
<div class="inner">
<span>Most inner #3</span>
</div>
</div>
</div>
Usually what we do need is mouseenter and mouseleave events, those aren't fired when user enters (ou leaves) a child element. In your case you need the old mouseout and mouseover events, that are trigged in that cases.
In the comments you've post a working fiddle: https://jsfiddle.net/ddsxxeer/1/
:)

Issue when animating on hover effects with callbacks

So I am having this issue when I am using the hover event in jQuery. I have two containers side by side. I have hover events on both of them. When hover, a div with additional info slides up into frame. When you hover off, it slides back down.
Simple right? When you hover on an element it should remove the "hide-me" class and start sliding the info up (animating). When you hover off of an element the "hide-me" class should be removed once the animation is complete.This works fine when you hover on and hover off onto an element that is not a grid-item. When you hover off of an item onto another grid-item it seems to just add the class "hide-me" to the currently hovered element. Even though the hover off event hasn't fired yet.
Anyways enough talk here is the code on JS Fiddle:
https://jsfiddle.net/joemoe_1984/2k22yLmd/2/
For testing here is what works:
Hover from below/above image then hover out from below/above image
For testing how it doesn't work:
Hover from below/above image then hover out onto other image
UPDATE
Just to clarify a bit as I had an answer that got me the effect I wanted but didn't exactly solve the issue I was having exactly. I would like to know why the animation callbacks on complete don't properly work when hovering from one image to the other. This is the part that has been bugging me the most. When you hover on an image and then out it removes the class on hover then adds the class after the animation called from the hover out event finishes. This is the expected behaviour. When I hover over an image then onto the other image you will see that instead of adding the class to the first image on hover out, it adds it to the image you are current hovering. Its as if the animation callback is calling the wrong callback function once it animates up on hover.
The on hover state should never have the class added. It should be removed at this point. The class should also not be added during any of the animation states.
Just in case links aren't ok, here is the full html, css and javascript:
HTML
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
CSS
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
Javascript
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height).removeClass('hide-me');
$info.stop().animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});
Try substituting using .show() after call to .stop() for .removeClass('hide-me') at hover_in
$(document).ready(function() {
$('.grid-item').hover(hover_in, hover_out);
function hover_in(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.css('top', target_height) //.removeClass('hide-me')
.stop()
.show()
.animate({
'top': 0,
}, 500, function() {
console.log('animated up');
});
}
function hover_out(e) {
$info = $(e.currentTarget).find('.grid-info');
target_height = $(e.currentTarget).height();
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$info.addClass('hide-me');
});
}
});
.grid-item {
width: 25%;
float: left;
overflow: hidden;
}
.grid-item img {
max-width: 100%;
height: auto;
}
.grid-inner {
position: relative;
display: block;
}
.grid-info {
position: absolute;
background: blue;
color: white;
width: 100%;
height: 100%;
}
.hide-me {
display: none;
}
.middle-align {
position: relative;
top: 50%;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<body>
<h1>Animation grid</h1>
<div class="grid-container">
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
<div class="grid-item">
<a href="#" class="grid-inner">
<div class="grid-image">
<img src="http://vignette3.wikia.nocookie.net/metroid/images/8/86/Samus_artwork_11.jpg/revision/latest?cb=20100516174330" alt="">
</div>
<div class="grid-info hide-me">
<div class="middle-align">
<h4 class="grid-title">Some title</h4>
<div class="grid-details">
This is some info about this item
</div>
</div>
</div>
</a>
</div>
</div>
</body>
jsfiddle https://jsfiddle.net/2k22yLmd/3/
Ok. So I figured it out. It turned out to be a scope issue. The problem stemmed from using e.currentTarget (or this) within the hover event scope. I stored that instance into a variable and then later used it in the callback of the animation sequence.
It appears that the current target changes from when the animation callback uses it giving me the unexpected results. For the animation callbacks I should have used the instance (this) within the scope of the animation callback function like so:
$info.stop().animate({
'top': target_height,
}, 500, function() {
console.log('animated down');
$(this).addClass('hide-me'); // this refers to the current animated object. This is the correct one.
$info.addClass('wrong-one'); // $info refers to the current hover event target which is the on hover item when it should be the hover off item. This is incorrect
});
You can test it out and see that going from one image to the next will now add the class hide-me to the correct one and add the class wrong-one to the currently hovered item which is not the expected behaviour I was looking for.
Thanks to everyone for pitching in on the answers and providing alternative solutions but this was real issue for me.

jQuery drag and drop colour div to change background of another

I have the following HTML, containing 4 <div>'s - 2 are doors and 2 are colors, as you can guess from their id.
I'd like to be able to drag either colour to either door (such as blue on the left door and black on the right) and change the background colour on the style.
<div id="door1" style="background: #fff;"></div>
<div id="door2" style="background: #fff;"></div>
<div id="black"></div>
<div id="blue"></div>
I'd be grateful even if someone could point me in the right direction at least.
You should initialize your color <div>'s as draggable and door <div>'s as droppable widgets using .draggable() and .droppable() methods respectively.
Then you can use the drop event handler of droppable for changing the background color. Inside the handler, you can access the droppable using this and dragged element using ui.draggable as shown below:
$(".color").draggable({
revert:true
});
$(".door").droppable({
drop: function(e, ui) {
console.log(ui.draggable)
$(this).css("background-color", ui.draggable.attr("id"));
}
});
.door {
display: inline-block;
width: 50px;
height: 120px;
border: 1px solid;
margin: 5px;
}
.color {
float: right;
width: 50px;
height: 50px;
}
.white {
background: #fff;
}
#black {
background: #000;
}
#blue {
clear: left;
background: royalblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.min.js"></script>
<div id="door1" class="door white"></div>
<div id="door2" class="door white"></div>
<div id="black" class="color"></div>
<div id="blue" class="color"></div>
Side note: I've removed the inline css and is using css classes, So that you can avoid duplication of styles and keep your HTML clean. You can read more about Why Use CSS # MDN
On the stop event of "draggable" check which div was the target (getting 'left' and 'top' attributes of the div that was dragged) and paint it with the color from the div that was dragged.

Categories