how can set up drag and drop to allow dragging of one element multiple times
i have made something like this http://jsfiddle.net/28SMv/3/ but after draging an item from red to blue the element loses its "draggability" and i cant drag it once more and more.
adding revert:true to draggable seems to work but then i need to remove helper:'clone' cant use them at the same time
If you drag an item & release without dropping, it stops being draggable. I'd remove all droppable stuff from that jsfiddle example, just put a bunch of draggables on the screen & try with that.
One possible solution is to rebind draggables after you're done dragging. Think:
function rebindDraggables() {
$('...').draggable({
...
stop: function() {
rebindDraggables();
}
})
}
I'm not sure why in your examples draggables cease to be draggable after the first time. The jQuery docs might explain this.
You're duplicating/cloning your elements, so the new one obviously won't be draggable. You could make it draggable, although that's much too much work. Just move the original via .append(). Note that when you append an existing object to another element, it will remove the original from its place. That seems to me like what you want to do.
Example: http://jsfiddle.net/28SMv/7/
You might want the items to be transferable back into the original div: http://jsfiddle.net/28SMv/8/
Note that I'm using jQuery 1.4.4 there, when you switch over to 1.5 it doesn't work. Not sure if that's a bug, or a feature of jQuery. My guess is that it's a bug of 1.5.
Related
I was testing around with the jQuery's drag and drop feature, and I am getting the following error in the JSconsole:
Uncaught TypeError: Cannot read property 'options' of undefined
I am trying to do a board game that you move pieces around, basically, like this:
The board is a table, empty squares are empty <td></td>
the non-empty TDs have <div class="..."></div> inside, the div class is either drag or nodrag (depending on whose turn is)
When dragging, what jQuery does is to give position relative and adjust the top/left
When dropping, what I am doing is to get the old and new squares, and use appendTo(), and in the case there is a div, I first remove() it
After a valid drop, I toggle the classes drag and nodrag, first removing the droppable attribute, then adding this to the new draggable
Here is the two crucial parts of the code (and here a jsFidle):
function toggleDrag(){
//remove the (old) draggables
if($(".drag").data("draggable")){//prevent crash when nobody is draggable
$(".drag").draggable("destroy");
}
//swapp classes
var tmp=$(".drag");
var tmp2=$(".nodrag");
tmp.removeClass("drag").addClass("nodrag");
tmp2.removeClass("nodrag").addClass("drag");
//make the (new) draggables
$(".drag").draggable({
revert:"invalid"
});
}
and inside every square (<td>):
$("td").droppable({
drop:function(ev,ui){
var tar=$(this);
var xdiv=$("#"+tar.attr("id")+" div");
//if the square is not empty
if(xdiv.length){
xdiv.remove();//remove piece
}
//I removed styles to reset Top/Left to 0
//append_TO_ moves the div
ui.draggable.removeAttr("style").appendTo(tar);
//I call the toggler funcion
toggleDrag();
}
});
Note: I am well aware that if you drop the piece in the same square that it was dragged, really bad things happen, in my full code I sanitize the droppables to only allow legal moves
Any ideas why this perfectly working code is triggering this console error?
You're seeing this error because destroying the draggable element inside the drop handler (apparently) isn't allowed.
One hacky way to work around this is to replace
toggleDrag();
inside your drop handler with
setTimeout(toggleDrag, 0);
After some more testing, I concluded that the stop: of draggables are triggered after the drop: of droppables, so I just moved toggleDrag() to here:
$(".drag").draggable({
//... ,
stop:function(ev,ui){
toggleDrag(); //a check is needed to make sure it was dropped on dropables though
}
});
The old problem was also triggered if you dropped a piece outside the board (and while it was slowly returning) and you quickly move other piece. This fixes this too.
I'm having a problem with my project, on combination with jQuery/Coffeescript.
On my homepage I have a block with text, with an arrow underneath it.
Under there, there are buttons, and every time I have my mouse over one of those buttons, I want the text block + arrow to move.
I do this with the jQuery UI library, with the method hide and show.
In my CSS code I made several classes: .position1, .position2 and .position1. Every time over hover with my mouse over one of the buttons, I want the text block to move to a specific position, so I change it's class (if someone has a better solution, I would gladly like to hear it).
Now the problem I'm having, is that sometimes the arrow hides and appears multiple times after each other (especially when I move my mouse very fast between the buttons)
A simple (partial) version of my jQuery is as follows:
var appear_arrow = function(to_position, show_delay) {
removeClasses($('.arrow'));
$('.arrow').addClass(to_class);
$('.arrow').delay(show_delay).show('slide', 'slow');
};
var to_position1 = function() {
$('.arrow').hide(0);
$('.text_block').hide(appear);
switchClass($('.text_block'));
$('.text_block').show(appear);
appear_arrow('position1', delay);
};
$('.button1').hover(
function() {
to_position1();
},
function() {}
);
My question, does anybody know why sometimes the arrow is appearing multiple times. Or does someone has a suggestion how to better do this?
jQuery queues up all its animations on a given Element rather than resetting it first.
$("selector").stop(); // stops animations on matched elements and resets queue
A stop().fadeIn('slow') however will start from the opacity the element had when you called stop, which could be solved by for example hiding/showing it immediately, then doing a full fade at the new location - whatever looks best for you.
On a side note:
Seems you wrote wrapper functions for jQuery's removeClass and toggleClass methods.
removeClass() if called without arguments removes all classes, so you could possibly just use those if in a jQuery context anyway (assuming your methods have no extra functionality).
Seeing how often you call $('.arrow') you may want to cache your selectors, at least per iteration, then pass it to appear_arrow().
var $arrow = $('.arrow')
I am searching for plugins/scripts that provide a toolbar when hovering elements of a big list. Almost like in this question:
JavaScript/HTML hover menu/toolbar
However, I don't want it to be a css-menu-like one. As I said, It will be a very big list and I would like its markup not to be duplicated n times. So I need a javascript that will move the same toolbar from list element to list element when they're hovered.
I know the YUI2 tooltip applies this strategy of moving the tooltip element, and changing the contents at display, but it's only for informative text displaying. I can't add buttons to it, and it's positionned according to the actual mouse position, and not to the element hovered.
ps: I tagged this question jQuery because the project is using it but i'm open to any framework-dependant or not solution.
Something like this should work:
var toolbar = $('#toolbar');
$('#yourTable').delegate('.has-tooltip', 'mouseenter', function() {
toolbar.insertBefore(this);
}).delegate('.has-tooltip', 'mouseleave', function() {
toolbar.detach();
});
The delegate will trigger for those events on elements matching .has-tooltip which are inside #yourTable.
I am using Flowplayer's jQuery Tools framework (specifically the tooltips plugin) in a table, in addition to jQuery UI calendar.
Each row of the table has the ability to insert a row above and below it.
When doing this I am cloning the clicked object (events and objects) and inserting it directly above or below.
After adding a new row, I refresh the table, generating new id's for my elements, reinitializing the datepicker, and attempting to reinitialize the tooltip.
I am searching for a way to destroy it altogether from the instance and reapply it.
I am looking for something similar to the datepicker('destroy') method.
$j($editRow).find('input.date').datepicker('destroy').datepicker({dateFormat: 'mm-dd-yy', defaultDate : defaultDateStr});
I have already attempted to :
to unbind the mouseover and focus events : when reinvoking tooltip, it automatically goes for the object it was made from.
hide the tooltip DOM element, remove the tooltip object from the target, and reapply it. The same thing happens as (1)
Is there way I can create a destroy method myself?
I tried kwicher's method, and could not get it to work. Although I was trying to alter the minified code, and I'm not entirely sure I found the right place to make the change.
I did, however, get this to work. ValidationFailed is a class I am applying to all the input fields that are also having tooltips applied to them.
$('.validationFailed').each(function (index) {
$(this).removeData('tooltip');
});
$('.tooltip').remove();
I tried this several different ways, and this was the only combination that allowed me to add additional tool tips post-removal, without preventing the new tooltips from working properly.
As best I can tell, the tooltip class removal handles getting rid of the actual tooltip divs, whose events are also wired up directly. The .removeData allows the tooltip to be re-bound in the future.
Building on your ideas and Tom's answer, I found that three things are necessary:
remove the 'tooltip' data from the tooltip target element
unbind event listeners from the tooltip target element
remove the element (assuming you're using this tooltip approach to allow for arbitrary HTML in your tip)
So, this simple function should do the trick. Just pass it a jQuery object containing the target elements of the tooltips you want to destroy.
function destroyTooltips($targets) {
$targets.removeData('tooltip').unbind().next('div.tooltip').remove();
}
If you still need it you can do as follows:
- in the tooltip implementation file add the following function
destroy: function(e) {
tip.detach();
}
somewhere in :
$.extend(self, {
...
I have after the last native function.
Then when you want to remove the tip, fire:
$(.tip).data('tooltip').destroy();
It should do the trick
K
if($element.data('ui-tooltip')) {//if tooltip has been initialized
$element.tooltip('destroy');
}
Maybe it's too late... ;-)
But here you can find all methods of 'tooltip': http://www.w3schools.com/bootstrap/bootstrap_ref_js_tooltip.asp
I leave the tip for someone who could pass by, having the same problem: dealing with different 'tooltip' actions/objs.
I am having a dilemma in the logic of this particular issue. Forgive me if this is quite newbie question but I'd rather have a solid bg on it.
There are a lot of examples of this all around the web where you click on an element to display another element. such case may be a menu that when you hover your mouse on it (or click on it) its get displayed. Later the element gets hidden either on mouse out, OR CLICKING ON ANY OTHER ELEMENT.. so, how is this achieved? I am sure the solution is not to bind a "hideElem" function on all the elements.
regards,
I haven't done it in a while, but an easy solution is to add a click event to the top of the DOM tree that will close the open element. Here's an example in psuedo-javascript:
document.body.onclick = function() {
element.style.display = "none";
}
If you need complex behaviors inside the "shown" element, make sure your preventing the necessary events from propagating up the DOM tree.
element.onclick = function(e) {
e.stopPropagation()
}
In general, the logic is the other way around (at least with menus) i.e. the element in question is hidden until a state-event unhides it, then hidden again as dictated. The point being that the hiding/unhiding logic is usually tied to the element itself, not everything else on the page.
As to how it's done, methods vary. There are lots of Javascript solutions, mostly along the lines of those already outlined, but menus can also be done purely with CSS - typically utilising the display: none; property, though you can also do stuff like setting/unsetting a negative margin so that the element is moved 'off and on the page'.
To use some of my own work by way of example:
Drop-down menu with Javascript
Drop-down menu with jQuery
Drop-down menu with CSS
$('#target').bind('click', function(event)
{
var $element = $('#element');
$element.show();
$(document).one('click', function()
{
$element.hide();
});
// If you don't stop the event, it will bubble up to the document
// and trigger the click event we just bound.
// This will hide the element right now just after showing it,
// we don't want that.
event.stopPropagation();
}
You have to keep in mind that a Javascript event goes up and down the whole tree when begin fired. So you can bind event listeners to any parent when you want to listen for an event on many elements.
This is called event delegation.
A cheap way to do it potentially is to bind an event handler to the "(on)blur" event of the clickable item and/or it's target. If your design allows.
That is one way to do it.
You could also write a method that traps (hooks into) all 'click' events regardless of the element, and hide your menu from there.
JQuery would make this task easier for you.
step 1- use a javascript library so you can have the code be as cross browser as possible - otherwise you have to cater to two different event models between internet explorer and gecko/webkit based browsers. JQuery, Mootools, YUI - all will handle this for you - there are more but those 3 are my favorite and are well documented.
step 2 - you prob would want to implement a clickshield for this - essentially a block-level dom element that is absolutely positioned over your entire page with a higher z-index than the rest of the page. attach a click event to that, and you can perform your logic for hiding elements on the page. The clickshield could easily have javascript code expand it to the width -height of your page post DOM rendering using the methods of any of the aforementioned javascript libraries.