Change dragging object and restore it after dropping it - javascript

please help me, I know in general how to use the draggable and droppable classes, but I can not find a way to achieve this:
I have a large-sized image that I need to drag and drop into a div.
1) while dragging, instead of moving around the large-sized image, I want to use a small-sized image (I already have it, just need to change the src).
2) Once it reaches the target div, I would like to hide that dragged image and show again the large-sized image in its original place.
The only restriction is: "revert: invalid" must apply.
This is my code:
$("#big_img").draggable({
revert: 'invalid',
drag : function(e, ui){
//Change big image with a small version of it
$(this).attr("src").replace("/Large/","/Small/"); //<--this do nothing
}
});
$("#target").droppable({
drop: function(e, ui) {
alert("was added"); //<-- no problem here.
//Restore the big_img
}
});
Thank you.

I think I solved it:
Using "helper", I can achieve to use other image instead, like this:
$("#big_img").draggable({
helper: return $("<img src='"+$(this).attr("src").replace("/Large/","/Small/")+"' />");
});
I just need to center it to the mouse cursor, but that I think won't be a problem. Then,
removing the dropped element won't be a problem either. So, I won't need to restore the image as it is not really moving. :)
If you have another alternative, I will be pleased to read it.

String.prototype.replace() does not modify the source string, but returns a new, modified string. Try the following:
$("#big_img").draggable({
revert: 'invalid',
drag : function(e, ui) {
$this = $(this);
$this.attr("src", $this.attr("src").replace("/Large/","/Small/"));
}
});

Related

jQuery: Multiple draggables and droppables?

I'm trying to use jquery draggable and droppable.
I have multiple draggables and multiple droppables on my page.
The drga and drop works fine but the issue is that when I drag and drop a div onto 1 droppable, it will get cloned in other droppables on my page as well... also, when I move the draggables inside the droppables, they get multiplied again.
To explain this issue, I've created this FIDDLE
and this is my entire code:
(function ($) {
$.fn.liveDraggable = function (opts) {
this.live("mouseover", function() {
if (!$(this).data("init")) {
$(this).data("init", true).draggable(opts);
}
});
return this;
};
}(jQuery));
$('.drag').liveDraggable({
helper: 'clone',
cursor: 'move'
});
var x = null;
$(".droppable").droppable({
drop: function(e, ui) {
var parent = $(".droppable");
var x = ui.helper.clone();
var img = $(x)
var leftAdj = (ui.position.left - parent.offset().left);
var topAdj = (ui.position.top - parent.offset().top);
if (x.hasClass("outside")) {
x.css({
left: leftAdj,
top: topAdj
});
x.removeClass("outside");
}
x.draggable({
helper: 'original'
});
x.find('.ui-resizable-handle').remove();
x.resizable();
x.appendTo('.droppable');
ui.helper.remove();
}
});
Drag the red divs onto the black divs and you should see the issue.
Could someone please advise on this issue?
Any help would be appreciated.
EDIT:
Getting close but still not quite there: https://jsfiddle.net/qkhunz8k/2/
Edit: Apparently I'm not communicating very well. Let me try this again. All of your droppables have the class droppable. As you say, of course they do. That is the purpose of the class.
However, in your code, when you say x.appendTo('.droppable'), this is the source of your duplicates. It is appending to every element which has the droppable class.
I'm not suggesting that you change or remove the droppable class. I'm not suggesting that you change all of your jquery selectors. I'm only suggesting that when you do your .appendTo, perhaps you should only be appending it to the droppable which is the target. Not all of them. Does that make sense? You can do this by doing x.appendTo(this). Just change that one line, and see if the duplicate problem goes away.
$(".droppable").droppable({
...
x.appendTo(this);
The only thing this change will do is change the number of elements your draggable gets appended to. It wouldn't cause any other changes. But I think it will solve your original problem.
As an aside, might I suggest that you would get better results by changing one other line? If you were to use the ui.draggable instead of the ui.helper, you might find that the css positioning would be a little easier to manage, and that you wouldn't need to manipulate the top and left properties so much. Just a thought.
var x = ui.draggable.clone();
updated modification of your fiddle here

Jquery UI. Droppable after element

I have an issue regarding jquery Ui droppable.
I need to drop an element before or after the element it's dragged over. Is there anyway to detect which element it's over, and then append/prepend it in the parent container.
Right now, I just drops in the end of the div, because of append, I'm a little clueless.
I made a fiddle to hopefully better illustrate my issue:
http://jsfiddle.net/tsxzf80u/
$('section').droppable({
accept:'.dragme',
drop:function(event, ui){
var div = $("<div />").addClass('full').html('test');
$(this).append(div);
}
});
Thanks in advance
If you make each of the divs inside of the section individually droppable, then use after(), seems to do what you want.
$('#fullId1, #fullId2').droppable({
accept: '.dragme',
drop: function (event, ui) {
var div = $("<div />").addClass('full').html('test');
$(this).after(div);
}
});
http://jsfiddle.net/tsxzf80u/2/

jquery drag/drop - activate dropzone with mouse not with center of dragged element

i want to drop some elements to another element.
my problem is the dropzone only gets activated when the middle of the dragged element is entering the dropzone.
the wished behaviour is to get the dropzone activated as soon as the mouse enters/hovers the dropzone.
i'm pretty shure this is a no brainer, but not for me...
i tried different options as example:
cursorAt:
snap:
handle:
but none of them helped anything...
i've just created a jsfiddle to explain my problem.
http://jsfiddle.net/FxEm7/3/
many thanks and kind regards
costal
Look at the tolerance option for droppable and set its value to pointer, as below:
$("#drop1, #drop2, #drop3").droppable({
tolerance: "pointer",
hoverClass: "ui-state-hover",
handle: ".msgHandler",
drop: function(ev, ui) {
console.log("msg_id = "+ui.helper[0].id);
console.log("drop_id = "+this.id);
}
});
The correct tolerance value is "touch".
http://api.jqueryui.com/droppable/#option-tolerance

jQuery drag and drop - checking for a drop outside a droppable

My apologies if this was answered in another question, I could not find an answer specific to my problem!
I'm trying to test whether a jQuery draggable is being dropped outside of a legal droppable. This would normally be solved 90% of the time by reverting the draggable, but I don't want to do that. Instead, I want to do one thing if the draggable is dropped onto a droppable (working great!), and something else if it is dropped outside of all possible droppables (currently getting the better of me!).
In a nutshell:
jQuery('#droppable').droppable(
{
accept: '#draggable',
drop: function(event, ui)
{
// awesome code that works and handles successful drops...
}
});
jQuery('#draggable').draggable(
{
revert: false,
stop: function()
{
// need some way to check to see if this draggable has been dropped
// successfully or not on an appropriate droppable...
// I wish I could comment out my headache here like this too...
}
});
I feel like I'm missing something really obvious...thanks in advance for any help!
Because the droppable's drop event fires before the draggable's stop event, I think you can set a flag on the element being dragged in the drop event like so:
jQuery('#droppable').droppable(
{
accept: '#draggable',
drop: function(event, ui)
{
ui.helper.data('dropped', true);
// awesome code that works and handles successful drops...
}
});
jQuery('#draggable').draggable(
{
revert: false,
start: function(event, ui) {
ui.helper.data('dropped', false);
},
stop: function(event, ui)
{
alert('stop: dropped=' + ui.helper.data('dropped'));
// Check value of ui.helper.data('dropped') and handle accordingly...
}
});
I see that you already got an answer; anyway I had this same problem today and I solved it this way:
var outside = 0;
// this one control if the draggable is outside the droppable area
$('#droppable').droppable({
accept : '.draggable',
out : function(){
outside = 1;
},
over : function(){
outside = 0;
}
});
// this one control if the draggable is dropped
$('body').droppable({
accept : '.draggable',
drop : function(event, ui){
if(outside == 1){
alert('Dropped outside!');
}else{
alert('Dropped inside!');
}
}
});
I needed that because I couldn't change the options of my draggables, so I had to work only with droppables (I needed it inside the awesome FullCalendar plugin).
I suppose it could have some issues using the "greedy" option of droppables, but it should work in most cases.
PS: sorry for my bad english.
EDIT: As suggested, I created the version using the jQuery.data; it can be found here : jsfiddle.net/Polmonite/WZma9/
Anyway jQuery.data documentation say:
Note that this method currently does not provide cross-platform support for setting data on XML documents, as Internet Explorer does not allow data to be attached via expando properties.
(meaning that it doesn't work on IE prior to 8)
EDIT 2: As noted by #Darin Peterson , the previous code doesn't work with more than one drop-area; this should fix that issue: http://jsfiddle.net/Polmonite/XJCmM/
EDIT 3: Example from EDIT 2 has a bug. If I drag "Drag me!" to the bottom droppable, then drop "Drag me too" to the upper droppable and then drop "Drag me too" outside, it alerts "Dropped inside!" So, don't use it.
EDIT 4: As noted by #Aleksey Gor, the example in Edit 2 was wrong; actually, it was more of an example to explain how to loop through all the draggables/droppables, but I actually forgot to remove the alert messages, so it was pretty confusing. Here the updated fiddle.
Try to use the event "out" of a droppable element.
This is the documentation
"This event is triggered when an accepted draggable is dragged out (within the tolerance of) this droppable."
If I'm right, this is what you need.
What is also possible is to create an element overlay over the whole page. If the element is dropped there you fire your event. Not the best, but I think the only way to do it. Because you need some other "droppable" item to fire these events.
The advantage of the following example, is that you don't need to change or know about the droppable code:
The draggable revert property can have a function(value){}. A value is passed as argument, indicating if helper was dropped onto an element (the drop element), or 'false' if not dropped on an element (drop outside or not accepted).
Note: you need to return the correct bool value from that
revert-function, in order to tell the helper to revert or not
(true/false). True means yes, take the helper back to its original
position, by moving it back in a slow motion (out-of-the-box). False means no, just
remove the helper abdruptly. Setting the revert property to 'invalid',
is a shortcut of saying
'yes, if dropped outside, then revert helper'
'no, if dropped on a droppable element and accepted, then kill the helper right away'.
My guess is that you can add current ui helper to draggable container with data property during start event. Then pick it up in the revert function from the data property. Then add a property to the helper, indicating if it was dropped or not. Then ultimately in the stop event, check this data property value, and do what you intended.
Order of event/function calls for draggable:
start-revert-stop
This could be an example:
jQuery('#draggable').draggable(
{
start: function(event, ui) {
$(this).data('uihelper', ui.helper);
},
revert: function(value){
var uiHelper = (this).data('uihelper');
uiHelper.data('dropped', value !== false);
if(value === false){
return true;
}
return false;
},
stop: function(event, ui)
{
if(ui.helper.data('dropped') === true){
// handle accordingly...
}
}
});
You can even return true in the revert function, and just remove the helper during the stop event instead, depending on the data('dropped') value with ui.helper.remove(). Or you could even explode it with CSS3 if you still have a bad day ;)
I add the solution I adopted since you can understand this very easily from the css classes of the object you are moving:
jQuery('#draggable').draggable({
stop: function(event, ui) {
if (ui.helper.hasClass('ui-draggable-dragging')) {
console.log('dropped out');
} else {
console.log('dropped successfully');
}
}
});
Old question and old answers mean that this "may" be a new solution. You (maybe) also wanted, as the question states, to know IF a draggable was dropped outside of a droppable. For me, in at least 95% of the cases, I don't really care IF, I just want things to go back to how they were without any changes being made WHEN that happens.
Setting revert to the string invalid accomplishes the desired behavior without any extra code or funky things to do.
$( '#draggable' ).draggable({
revert: "invalid",
stop: function( event, ui )
{
// whatever
}
});
Again, it won't tell you "if it was dropped outside of a droppable," but it will revert to the initial state if that happens.
This work for me:
<script>
$( function() {
$( "#draggable" ).draggable();
$( ".droppable" ).droppable({
drop: function( event, ui ) {
if( $(this) ){
$( "#draggable" ).draggable( "disable" );
}
},
});
} );

jQuery UI - dropped element -> from which div was it dragged

I have a problem with jQuery UI and get some information of a dropped item.
I have three areas on the screen:
<div id="area1"></div>
<div id="area2"></div>
<div id="area3"></div>
In these areas, I put elements which are draggable with jQuery UI.
Now if an element is dropped from one to another area, I will not only get the area number in which the element is dropped to, I also want the area number where the element was dropped before the new drop.
I created a full working example: http://jsbin.com/iyaya3/
There is a blue draggable element and if I drag it from area1 to area2, I want to have the alert message with "dragged from area1 - dropped to area2".
How can this be done?
Best Regards, Tim-.
Hey, I updated your jsbin - http://jsbin.com/iyaya3/3
It works like this:
Take initial parent element's id and save it on draggable using jQuery.data
When dropping it on droppable, update data
I've got two ideas:
1) You can put a class or ID on the elements in each div:
<div id="area1"><node class="from1"></node></div>
<div id="area2"><node class="from2"></node></div>
<div id="area2"><node class="from2"></node></div>
And then test for that when you have the item
2) Write a function to do the clone instead of relying on the drag and drop to do it for you (http://ui-dev.jquery.com/demos/draggable/#option-helper) and then test for the parent and store that (in a singleton outside the scope of the dragger) where you can get it later.
I think I would prefer the first (even if you don't have html access to add these classes, just add it with javascript)
In your draggable setup, add this:
start: function(event,ui){
ui.helper.data('from-id', $(this).parent().attr('id') );
}
This will attach, as data, the ID of the container from which the element is being dragged.
Then, in the droppable, you can have:
alert( 'I was dragged from ' + ui.draggable.data('from-id') );
Here's the updated jsBin.
Edit: The start function creates a closure, so $(this).parent().attr('id') continues to point to the original parent. One solution to this problem (if you wish to keep a start function) is to clear start when the drag stops:
stop: function(event,ui){
ui.helper.draggable({ start: null });
}
This will allow the data methods in the droppable handlers to update the from-id without being immediately reverted to the original value by the start function.
Here's a revised jsBin example.
$(element.draggable).parent().attr('id')) works for me
I removed the duplicated code and solved the problem by saving the previous element id by the data() function.
JS Bin
<script type="text/javascript">
$(document).ready(function() {
$('#area1').append('<div class="shoulddraggable" style="width:100px;height:100px;top:0px;left:0px;background-color:blue;" data-elementid="100"></div>');
$(".shoulddraggable").draggable({
scroll: false,
revert: "invalid",
scope: "items",
});
$(".shoulddraggable").data('previousId', 'area1');
$('.droppable').droppable({
scope: "items",
drop: function(event, ui) {
alert('Previous container id: ' + ui.draggable.data('previousId'));
alert("Element: "+ui.draggable.data("elementid")+" dragged into" + $(this).attr('id'));
ui.draggable.data('previousId', $(this).attr('id'));
}
});
});
</script>
</body>
</html>

Categories