Unable to re-position a draggable element - javascript

I have a div that I made draggable and am trying to give the user the ability to build some content. I have it doing most of what I want:
I drag a div from the left toolbar and it lands in the container on the right. If you don't put it in that container, it gracefully floats back to it's original position.
My issue is: Once I drop it I can't move it again to put it in another spot within the same container. How can I fix this?
Note: I am using jQuery: 1.11 and jQuery UI 1.10
// Draggable elements
$("#draggable_div").draggable({
cursor : 'move',
snap : '#target_builder',
revert : function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top : 0,
left : 0
};
return !event;
},
stop : function() {
// do I need to re-initialize it here?
}
});
$("#target_builder").droppable();
<div>
<div>
<div id="draggable_div" style="color: #fefefe; background: #222; width: 100px; height: 100px;">
<p>Div</p>
</div>
</div>
<div>
blank content
</div>
</div>
Edit:
jsfiddle: http://jsfiddle.net/KbQDQ/
it seems to work her, but not in my real code... hmmm...

if you remove
return !event;
the element will stay where you leave it :)
here's the correct code:
// Draggable elements
$("#draggable_div").draggable({
cursor : 'move',
snap : '#target_builder',
revert : function(event, ui) {
$(this).data("uiDraggable").originalPosition = {
top : 0,
left : 0
};
},
stop : function() {
// do I need to re-initialize it here?
}
});
$("#target_builder").droppable();

I figured it out. I am using the Twitter bootstrap framework. I removed the classes (not shown above) and all works well.

i think that
return !event;
&
stop : function() {
$("#draggable_div").draggable( "destroy" );
}
make some error please remove it & try again once

Related

Javascript Accordian

I have a simple accordion working, except for one thing. I would like to be able to re-click the same accordion item again, and be able to set height to '0'.
Currently, the open accordion item closes when I click a different accordion item, which is exactly what I want to do — but I also want the ability to re-click the open accordion item and have that one close, when clicked. See working example below:
https://codepen.io/celli/pen/BaNLJWb
// set heights to 0
gsap.set('.content', {
height: 0
});
// click function
$('.accordianItem').click(function() {
if ($('.accordianItem').hasClass('on')) {
gsap.to($('.content'), {
duration: .25,
height: 0
});
$('.accordianItem').removeClass('on');
}
gsap.to($(this).children('.content'), {
duration: .25,
height: "auto"
});
$(this).addClass('on');
});
What code can I add to add this extra functionality?
I have modified your code by adding another if that checks if the element clicked has 'on' class already. It should now work as you intended it to (hide when the user clicks on the already opened header).
// set heights to 0
gsap.set('.content', {height:0});
// click function
$('.accordianItem').click(function() {
if($(this).hasClass("on")){
gsap.to($('.content'), {duration:.25, height:0});
$('.accordianItem').removeClass('on');
}
else{
if ($('.accordianItem').hasClass('on')) {
gsap.to($('.content'), {duration:.25, height:0});
$('.accordianItem').removeClass('on');
}
gsap.to($(this).children('.content'), {duration:.25, height:"auto"});
$(this).addClass('on');
}
});
You can do this much more simply than how you're currently doing it:
// Create the animation that you need
const tl = gsap.timeline({paused: true});
tl.to('.content', {duration: 0.25, height:0});
// Set the timeline to its end state
tl.progress(1);
// Toggle the timeline's direction
$('.accordianItem').click(function() {
tl.reversed() ? tl.play() : tl.reverse();
});
Demo
I highly recommend checking out the GreenSock forums. They're super useful and you can get quick help from people who are experts in GSAP and web animation :)

jquery .ui-selectable with scroll

I have a div with fixed height
<div style="height:300px; overflow-y:scroll">
<div class="selectable_div">
....
</div>
</div>
And I init selectable like this:
$( ".selectable_div" ).selectable({
But when I select content in .selectable_div scroll gets blocked and div is not scrolling. I want it to scroll while selecting on mouse wheel and when I just select and hold selection and move mouse down.
What do I do?
I found a plugin but don't want really to use 3d party plugins cause they might break something
UPD : the entire snippet if u ask(it very big, so I don't think it will help)
$( ".selectable_wrap" ).selectable({
filter: ".word_item",
cancel: '.cancel_selection',
stop: function(){
self.words.filter(x => x.selected).forEach(function(w){
w.selected = false
})
self.words_ids=[]
// alert($( ".ui-selected.word_item").size())
$( ".ui-selected.word_item", this ).each(function() {
let word_index = $(this).attr('data-count')
word = self.words[word_index]
word.selected = true
self.words_ids.push(word.id)
});
self.get_phrases_by_words(JSON.stringify(self.words_ids))
},
}).disableSelection();

Droppable doesn't attach quickly enough to dynamically generated element in Jquery

This seems like a really annoying bug I have been trying to solve for days. I am making a sortable list. When I click and drag grey item and I hover over the red I need a spacer to show up below it so I can drop it in the newly shown spacer. I try to bind a draggable over the spacer (so I know if the user drops it onto it) but I just can't get the spacer to recognise when it has something 'over it' unles >>>> and here is the gotcha while I drag and hold and move my element to the side of the screen.
To recreate :
Click and hold the grey tab
Drag it over the red (at this point the yellow spacer shows)
Drag it onto the yellow but don't let go of the mouse (notice nothing writes to the console).
Now repeat the experiement but before going over the yellow spacer wiggle the draggable grey item at the side of the screen now go over the yellow spacer and hey presto it detects it and writes a message to the console which means the code has worked. Does anybody know what the hell is going on? I have been stuck on it for days!
The code:
$('.draggable').draggable({
revert: true,
revertDuration: 30,
stop: function () {
$('.spacer').removeClass('open');
var dragged = $(this);
dragged.css('z-index', '1000');
},
start: function (event, ui) {
var dragged = $(this);
dragged.css('z-index','1009');
}
});
$('.hoverable').droppable({
over: function (event, ui) {
var target = $(event.target);
var newElem = target.next().append('<div id="spacer" style="display:block; height:30px;width:100px;background-color:yellow;"></div>');
newElem.on().droppable({
over: function() {
console.log('sdfsd');
},
tolerance: "touch"
});
}
});
<body>
<div class="draggable"></div>
<div class="hoverable"></div>
<div class="d"></div>
</body>
.draggable{
width:100px;
height:30px;
background-color:gray;
}
.hoverable{
width:100px;
height:30px;
background-color:red;
}
.spacer{
width:100px;
height:30px;
background-color:yellow;
}
The JsBin is here...
http://jsbin.com/golel/1/
The problem with your code is that your calls to $('.draggable').draggable() and $('.hoverable').droppable() are happening on the current DOM, so those functions are not executed on new DOM elements. You somehow need to trigger these functions on new elements as well. (If you're only worried about dynamic drop regions, you can ignore this aspect for the draggable() call.)
Here's an example of what I mean:
function makeDroppable(selector) {
$(selector).droppable({
over: function (event, ui) {
var target = $(event.target);
var newElem = target.next().append('<div id="spacer" style="display:block; height:30px;width:100px;background-color:yellow;"></div>');
makeDroppable(newElem);
}
});
}
makeDroppable('.hoverable');

Why the box disappear immediately?

I want the mouseover on the coverImg then show the coverInfo
the coverInfo show the title and the description of the image
then the coverInfo do show
but I want the coverInfo stay and clickable when mouserover on itself
but it disappear immediately.
So what's the point I have missed?
The HTML
<div class="workshop_img">
<div class="coverInfo"></div>
<a href="#">
<span class="coverImg" style="background-image:url('images/work/show1.jpg')" title="Chictopia "></span>
</a>
The CSS:
.coverInfo {
position:absolute;
width: 200px;
height:200px;
background:rgba(0,0,0,0.5);
top:30%;
left:30%;
display:none;
}
see the jQuery code
$(function() {
$(".coverImg").each(function() {
//make the background image move a little pixels
$(this).css({
'backgroundPosition' : "-40px 0"
}).mouseover(function() {
$(this).stop().animate({
'backgroundPosition' : " -20px -60px "
}, {
duration : 90
});
//shwo the info box
var content = $(this).attr("title");
$("<div class='coverInfo'></div>").text(content).prependTo($(this).parent()).fadeIn("fast");
}).mouseout(function() {
$(this).stop().animate({
'backgroundPosition' : "-40px 0"
}, {
duration : 200,
});
$(this).parent().find(".coverInfo").stop().fadeOut("fast");
})
})
});
</div>
EDIT:
I have searched a lot and find something similar, I took them and the answer given below together to solve my problem, here is the code:
$(function() {
$(".coverImg").css({
'backgroundPosition' : "-40px 0"
}).mouseenter(function() {
var box = $(this).parents(".workshop_img").find(".coverInfo");
var content = $(this).attr("title");
var info = box.text(content);
$(this).stop().animate({
'backgroundPosition' : " -20px -60px "
},90);
info.show();
}).mouseleave(function() {
var box = $(this).parents(".workshop_img").find(".coverInfo");
var content = $(this).attr("title");
var info = box.text(content);
$(this).stop().animate({
'backgroundPosition' : "-40px 0"
},200);
info.stop().hide();
});
});
It has just been clean, but do not work fine.
What's the problem?
The new box shows immediately because it is not initially marked as hidden. .fadeIn() only fades in something that is initially not showing.
You can make it initially not visible like this:
$("<div class='coverInfo'></div>").text(content).hide().prependTo($(this).parent()).fadeIn("fast");
You also can get rid of the .each() iterator you're using. You don't need it. You can just use:
$(".coverImg").css(...).mouseover(...).mouseout(...);
You don't need the .each() at all.
I'd also suggest you use .hover(fn1, fn2) instead of .mouseover(fn1) and .mouseout(fn2).
And, it looks like you are creating a new object and inserting it on every mouseover event such that multiple such objects will pile up in the page. You should either .remove() the object in the mouseout function or you should reuse a previously existing element if it exists in the element rather than creating more and more of them.
Sometimes when you are using the events for mouse hovering and you are also changing the page, the change to the page can cause the element to lose the mouse hover which then hides the change to the page and then it all starts over again. I can't tell for sure if that is happening in your case (I'd need a working example to play with to see), but it seems possible.

JQuery UI resizable does not support position: fixed; Any recommendations?

JQuery UI's .resizable function does not support position: fixed; elements. The moment you try to resize them it switches their position attribute to absolute. Any recommended fixes?
I have some chat windows that pop up and are draggable around the document. They are position fixed so that they don't scroll with the page behind them. They all work perfectly until you try to resize a window, that's when it transitions to position: absolute; and then gets left behind when the page scrolls.
I tried handling the resize stop event and changing the position to fixed:
stop: function (event, ui)
{
$(chatWindow).css('position', 'fixed');
}
This doesn't work because the positioning (top: and left:) are not correct for the fixed element and when you stop resizing the element switches to fixed positioning and jumps to weird places on the page. Sometimes jumps out of the page boundries and is lost forever.
Any suggestions?
To get over this problem I wrapped the .resizable() block with the .draggable() block:
<div id="draggable-dealie">
<div id="resizable-dealie">
</div>
</div>
the corresponding js:
$("#draggable-dealie").draggable();
$("#resizable-dealie").resizable();
and ensure you have the property position:fixed !important; set in the #draggable-dealie CSS:
#draggable-dealie {
position:fixed !important;
width:auto;
height:auto;
}
I have a demonstration at: http://jsfiddle.net/smokinjoe/FfRRW/8/
If, like me, you have a fixed div at the bottom of the page, then you can just add !important to these css rules to make it stick at the bottom :
.fixed {
position: fixed !important;
top: auto !important;
bottom: 0 !important;
left: 0;
right: 0;
}
And just make it resizable by its north border :
$('.fixed').resizable({
handles: "n"
});
Simply force position:fixed on the element when resizing starts and when resizing stops.
$(".e").draggable().resizable({
start: function(event, ui) {
$(".e").css("position", "fixed");
},
stop: function(event, ui) {
$(".e").css("position", "fixed");
}
});
JSFiddle: http://jsfiddle.net/5feKU/
No beauty but how about saving the position (top and left) in separate vars on the start of the resize (I think the method is called "start")?
UPDATE (Thank you for the comment... The event fires too late):
As JqueryUI generates a second object "ui" on making a object resizable it gives that ui-object a field: ui.originalPosition... That should be the position of the fixed element before the resizing...
Here's the solution I came up with, it's a little more code than I'd like, but it fixes the problem:
$("#test").resizable({stop:function(e, ui) {
var pane = $(e.target);
var left = pane.attr("startLeft");
var top = pane.attr("startTop");
pane.css("position", "fixed");
pane.css("top", top);
pane.css("left", left);
}});
$("#test").draggable({create: function(e, ui) {
var pane = $(e.target);
var pos = pane.position();
pane.attr("startLeft", pos.left + "px");
pane.attr("startTop", pos.top + "px");
}, stop: function(e, ui) {
var pane = $(e.target);
pane.attr("startLeft", ui.position.left + "px");
pane.attr("startTop", ui.position.top + "px");
}});
This stores the top and left position in the html element (needs xhtml doctype to be valid) and uses that information to set the position at the end of the resizing event.
This is a dirty solution but works for me.
this.resizable({
start:function (event, ui){
x =ui.originalPosition.left+ $(ui.originalElement).parent().scrollLeft()
y = ui.originalPosition.top+ $(ui.originalElement).parent().scrollTop()
},
resize:function (event, ui){
$(ui.originalElement).css('left' , x);
$(ui.originalElement).css('top' , y);
}
I had that problem today, and I absolutely hate "un-aesthetic" workarounds... So I decided to experiment a little to see if there wasn't a "better" solution ...and at some point I had a hunch:
html:
<div class="fixed"></div>
javascript (jquery):
$('.fixed').resizable();
$('.fixed').draggable();
css:
.fixed{
position: fixed !important;
}
Jquery just got outplayed by CSS, damn!

Categories

Resources