How to get class name of draggable element? - jquery-ui

Within the droppable function how can I get the draggable element's class name which is currently being dragged.
$( ".drop" ).droppable( { accept: handleFunction } );
function handleFunction(draggable){
//How to get currently dragging element's class name
}

I don't think you've got the accept option's usage correctly. It does not get the draggable currently being dragged, it tests the draggable that you just dropped in the droppable element. From the droppable documentation:
Function: A function that will be called for each draggable
on the page (passed as the first argument to the function).
The function must return true if the draggable should be accepted.
Regardless, what you get as a parameter is a jQuery element, not a JS object. You can test its classes in several ways:
$( ".drop" ).droppable( { accept: handleFunction } );
function handleFunction(draggable){
// This will return ALL classes attached to this draggable element as a string
// This is probably NOT what you need; it's VERY fragile
var className = $(draggable).attr('class');
// This returns a boolean for testing if myClass is present in the element's classes
// This is a very common function and probably what you want
var test = $(draggable).hasClass('myClass');
// Note return value should be a boolean.
return test;
}

Related

jQuery UI autocomplete widget - how to get a reference to the menu?

I want to be able to get a reference to the menu object that autocomplete builds, (so I can get the .attr("id") for example), but I'm not very familiar with jQuery/javascript. In the source, I found this:
https://github.com/jquery/jquery-ui/blob/1-9-stable/ui/jquery.ui.autocomplete.js#L182
so there is an object flying around, I just can't seem to find how to get hold of it.
So, for example, if I've got an input with an autocomplete bound to it like this:
// input = reference to the input text box on the form
input.autocomplete({
select: function(event, ui) {
// how to get the reference here?
// some things I've tried
// return input.menu
// return input.data("menu")
// and a few others but they didn't work either
}
});
I tried looking at the data object itself, but there were so many options I could spend all day looking at it and still not find what I'm looking for.
You can get the widget's reference by looking into dataset assigned to its root element (input). Then fetching menu property (and its underlying element) is kinda trivial. )
select: function(event, ui) {
// that's how get the menu reference:
var widget = $(this).data('ui-autocomplete'),
menu = widget.menu,
$ul = menu.element,
id = $ul.attr('id'); // or $ul[0].id
}
... as this within select function refers to the <input> when this function called as an event handler.
A simpler way to do this:
$(this).autocomplete('widget');
It does the same as:
select: function(event, ui) {
// that's how get the menu reference:
var widget = $(this).data('ui-autocomplete'),
menu = widget.menu,
$ul = menu.element,
id = $ul.attr('id'); // or $ul[0].id
}
It gives the ul list
$(this).autocomplete('widget').attr('id');

mouseleave not working in jquery

my mouseleave is not working in my jquery code
http://jsfiddle.net/alano/9Dr7T/29/
providing my js code below
mouseleave: function () {
$(this).find("div:last").remove();
}
The problem isn't with the mouseleave listener, the problem is how you're binding those event handlers and unbinding them for that matter. The div was being removed, but it was being readded with every mouseenter event. For some reason the mouseenter event wasn't being unbound when using the selector filter for .on(). It probably has something to do with the way bubbling occurs when using the selector filter.
When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
Now, I'm not 100% sure why just yet, but either way it will work if you use directly-bound handlers like so:
$('.specialHover').on({
mouseenter: function() {
$("<div class='cta'>add image</div>").click(function() {
var $me = $(this);
$me.parent().unbind('mouseenter').children('img').attr(
'src',
'http://www.onlinegrocerystore.co.uk/images/goodfood.jpg'
);
$me.remove();
}).appendTo(this);
},
mouseleave: function() {
$(this).find('div:last').remove();
}
});
See: http://jsfiddle.net/9Dr7T/35/
Did you tried this way:
mouseleave: function () {
$("div:last",this).remove();
}

jQuery UI – draggable 'snap' event

I'm looking a way to binding the snap event.
When I'm dragging an element over my surface and the draggable element is snapped to a declared snap position I want to trigger an event.
Something like this:
$(".drag").draggable({
snap: ".grid",
snaped: function( event, ui ) {}
});
Bonus point: with a reference to the .grid element where the draggable element was snapped.
The draggable widget does not expose such an event out of the box (yet). You could modify it and maintain your custom version or, better, derive a new widget from it and implement the new event there. There is, however, a third way.
From this question, we know the widget stores an array of the potentially "snappable" elements in its snapElements property. In turn, each element in this array exposes a snapping property that is true if the draggable helper is currently snapped to this element and false otherwise (the helper can snap to several elements at the same time).
The snapElements array is updated for every drag event, so it is always up-to-date in drag handlers. From there, we only have to obtain the draggable widget instance from the associated element with data(), and call its _trigger() method to raise our own snapped event (actually dragsnapped under the hood). In passing, we can $.extend() the ui object with a jQuery object wrapping the snapped element:
$(".drag").draggable({
drag: function(event, ui) {
var draggable = $(this).data("draggable");
$.each(draggable.snapElements, function(index, element) {
if (element.snapping) {
draggable._trigger("snapped", event, $.extend({}, ui, {
snapElement: $(element.item)
}));
}
});
},
snap: ".grid",
snapped: function(event, ui) {
// Do something with 'ui.snapElement'...
}
});
The code above, however, can still be improved. As it stands, a snapped event will be triggered for every drag event (which occurs a lot) as long as the draggable helper remains snapped to an element. In addition, no event is triggered when snapping ends, which is not very practical, and detracts from the convention for such events to occur in pairs (snapped-in, snapped-out).
Luckily, the snapElements array is persistent, so we can use it to store state. We can add a snappingKnown property to each array element in order to track that we already have triggered a snapped event for that element. Moreover, we can use it to detect that an element has been snapped out since the last call and react accordingly.
Note that rather than introducing another snapped-out event, the code below chooses to pass an additional snapping property (reflecting the element's current state) in the ui object (which is, of course, only a matter of preference):
$(".drag").draggable({
drag: function(event, ui) {
var draggable = $(this).data("draggable");
$.each(draggable.snapElements, function(index, element) {
ui = $.extend({}, ui, {
snapElement: $(element.item),
snapping: element.snapping
});
if (element.snapping) {
if (!element.snappingKnown) {
element.snappingKnown = true;
draggable._trigger("snapped", event, ui);
}
} else if (element.snappingKnown) {
element.snappingKnown = false;
draggable._trigger("snapped", event, ui);
}
});
},
snap: ".grid",
snapped: function(event, ui) {
// Do something with 'ui.snapElement' and 'ui.snapping'...
var snapper = ui.snapElement.attr("id"),snapperPos = ui.snapElement.position(),
snappee = ui.helper.attr("id"), snappeePos = ui.helper.position(),
snapping = ui.snapping;
// ...
}
});
You can test this solution here.
In closing, another improvement might be to make the snapped event cancelable, as the drag event is. To achieve that, we would have to return false from our drag handler if one of the calls to _trigger() returns false. You may want to think twice before implementing this, though, as canceling a drag operation on snap-in or snap-out does not look like a very user-friendly feature in the general case.
Update: From jQuery UI 1.9 onwards, the data() key becomes the widget's fully qualified name, with dots replaced by dashes. Accordingly, the code used above to obtain the widget instance becomes:
var draggable = $(this).data("ui-draggable");
Instead of:
var draggable = $(this).data("draggable");
Using the unqualified name is still supported in 1.9 but is deprecated, and support will be dropped in 1.10.
In jquery-ui 1.10.0, the above code doesn't work. The drag function is instead:
drag: function(event, ui) {
var draggable = $(this).data("ui-draggable")
$.each(draggable.snapElements, function(index, element) {
if(element.snapping) {
draggable._trigger("snapped", event, $.extend({}, ui, {
snapElement: $(element.item)
}));
}
});
}

jQuery Droppable element - conditional drop event based on item dropped

I have a problem that I can't seem to figure out. I'm trying to have a droppable element conditionally fire a different function based on the class of the item dropped. For the life of me I can't figure out how to do this. Here's the link: http://jsfiddle.net/643PC/22/
The pageContainer accepts Rows. Rows accept Spans. Spans should accept Actions and Fields and fire a different function based on which item is dropped. Any ideas?
Finished function with David's help:
function generalDrop(event, ui) {
var appendTarget = $(this);
if (ui.draggable.hasClass('field-item')) {
fieldDrop(event, ui, appendTarget);
}
else {
actionDrop(event, ui, appendTarget);
}
}
function actionDrop(event, ui, appendTarget) {
$(document.createElement('a'))
.addClass('btn btn-primary')
.attr('href', '#')
.text('Button')
.appendTo(appendTarget)
}
Change your generalDrop function to this:
function generalDrop(event, ui) {
if (ui.draggable.hasClass('field-item')) {
fieldDrop(event, ui);
}
else {
actionDrop(event, ui);
}
}

JQuery UI and event handling

I have a jQuery UI widget which attaches to a div and then listens to specific controls inside it (set via options). The problem is that in my event listener, this refers to the control that changed, not the element the widget is attached to. So how can I access the widget element?
_addressChanged: function () {
$(this).data("address").requiresValidation = true;
},
_bindEventHandlers: function () {
$(this.options.address1).bind("change", this._addressChanged);
$(this.options.address2).bind("change", this._addressChanged);
$(this.options.city).bind("change", this._addressChanged);
$(this.options.zip).bind("change", this._addressChanged);
},
Use the this._on() method to bind the handler. This method is provided by the jQuery UI widget factory and will make sure that within the handler function, this always refers to the widget instance.
_bindEventHandlers: function () {
this._on(this.options.address1, {
change: "_addressChanged" // Note: pass the function name as a string!
});
...
},
_addressChanged: function (event) {
// 'this' is now the widget instance.
// 'this.element', as suggested by sjsharktank, is the DOM element the widget was created on
},
Have you tried this.element?
From http://wiki.jqueryui.com/w/page/12138135/Widget%20factory:
this.element
The element that was used to instantiate the plugin. For example, if you were to do $( "#foo" ).myWidget(), then inside your widget instance this.element would be a jQuery object containing the element with id foo. If you select multiple elements and call .myWidget() on the collection, a separate plugin instance will be instantiated for each element. In other words, this.element will always contain exactly one element.

Resources