Use Methods from Dropped Object in JQuery - javascript

I would like to use a method of an dragged and dropped Object.
function Controller(){
$( "#container" ).droppable({
drop: function( event, ui ) {
var draggable = ui.draggable;
alert( "Dropped:" + draggable.attr('id'));
draggable.myMethod();
}
});
Could you explain why this doesnt work?
The alert shows that the right Object ist dropped,
but i cant use the method.
The Object looks like this:
function Icon(name) {
var name = name;
this.myMethod = function() {
alert("test")};
this.getInfo = function() {
var dataname = this.getName();
//BErtram
$("#" + dataname).draggable({ revert: "valid" });
//Bertram Ende
}
}
Edit:
If I invoke the Method this way:
drop: function( event, ui ) {
var draggable = ui.draggable;
alert(...);
var ic = new Icon("asdsa");
ic.myMethod();
},
it works, but I want to use the Method on the dragged Object, do I have to do some sort of typecasting?
Edit: Workaround
Finally i used a workaround, using a bool to check if there was a succesfull drop and invoking the method in draggable.stop if the boolean ist true. The state of the boolean is set to true in the droppable on a succesfull drop and set to false in draggable.start.

The problem is that myMethod is a function on the Icon object you create, however the ui.draggable is not an instance of Icon - so it has no myMethod method.

The ui.draggable value is a DOM element contained inside a jQuery object. You need a mechanism to map from the element back to the Icon that's responsible for it.
The simplest method is to use .data():
function Icon(name) {
$('#' + name).data('self', this);
...
}
and then retrieve that object in the event handler:
drop: function(event, ui) {
var draggable = ui.draggable;
var icon = draggable.data('self');
icon.myMethod();
}

Related

Cursor position in textbox inside jquery autocomplete callback?

Autocomplete using css class:-
$(cssClass).autocomplete({
minLength: 0,
focus: function() {
return false;
},
select: function( event, ui ) {
var cursorPos = $(this).prop('selectionStart');
console.log(cursorPos);// showing the proper cursor value
return false;
},
source: function( request, response ){
var cursorPos = $(this).prop('selectionStart');
console.log(cursorPos);// undefined ...?
}
});
When I am trying to get the cursor position using css class using jquery autocomplete, in one closure select I am able to successfully retrieve the value of current position but when the same is done in source closure the value is undefined.
Can someone please explain me why is that? and how to get the value?
To get the cursor position inside the source, you can try search event method. This method will be called once you type/change content in the input/text area and then only source method will be called. So, what you can do is, have a global variable cursorPos and in the search method, do the assignment as cursorPos = $(this).prop('selectionStart');
Inside the source method, you can get the global variable cursorPos value.
Your code can be modified as,
var cursorPos; // global var
$(cssClass).autocomplete({
minLength: 0,
focus: function() {
return false;
},
select: function( event, ui ) {
var cursorPos = $(this).prop('selectionStart');
console.log(cursorPos);
return false;
},
source: function( request, response ){
console.log(cursorPos); // refers the global var and returns the cursor pos
// add your logic
},
search: function( event, ui ){
cursorPos = $(this).prop('selectionStart');
}
});
By this way, you can get the cursor position inside the source method :)

Best way to silently bind window resize event to jQuery plugin without keeping a reference to the targeted element

I'm looking for best-practice advice.
I'm writing a small jQuery plugin to manage horizontal scroll on elements.
I need all the dom elements targeted by that plugin to update on window resize.
Fact is, my website is a full ajax 'app' so when I remove DOM elements, I need them gone so memory doesn't leak.
But I can't find a way to bind the resize event without keeping a reference to the DOM node.
EDIT :
Actually I need the resize handler to get the plugin-targeted elements at 'call' time, coz I don't want to keep any reference to those elements in memory, because I might call .html('') on a parent of theirs...
I did not paste all my code, just an empty shell. I already have a destroy method that unbinds handlers. But I'm generating, removing and appending html nodes dynamically and I the the elements targeted by the plugin to remove silently.
Kevin B stated I could override jQuery .remove method to deal with the handlers, but would have to load jQuery UI for it to work. I don't want that either..
Here is what I tried (attempts commented):
(function($) {
// SOLUTION 2 (see below too)
// Not good either coz elements are not removed until resize is triggered
/*
var hScrolls = $([]);
$(window).bind('resize.hScroll',function(){
if(!hScrolls.length) return;
hScrolls.each(function(){
if($(this).data('hScroll')) $(this).hScroll('updateDimensions');
else hScrolls = hScrolls.not($(this));
});
});
*/
// END SOLUTION 2
// SOLUTION 3 (not implemented but I think I'm on the right path)
$(window).bind('resize.hScroll',function(){
// need to get hScroll'ed elements via selector...
$('[data-hScroll]').hScroll('updateDimensions');
// I don't know how....
});
// END SOLUTION 3
var methods = {
init : function(options) {
var settings = $.extend( {
defaults: true
}, options);
return this.each(function() {
var $this = $(this),
data = $this.data('hScroll');
if (!data) {
$this.data('hScroll', {
target: $this
});
// SOLUTION 1
// This is not good: it keeps a reference to $this when I remove it...
/*
$(window).bind('resize.hScroll', function(){
$this.hScroll('updateDimensions');
});
*/
// END SOLUTION 1
$this.hScroll('updateDimensions');
// SOLUTION 2 (see above too)
hScrolls = hScrolls.add(this);
}
});
},
updateDimensions: function(){
var hScroll = this.data('hScroll');
// do stuff with hScroll.target
}
}
$.fn.hScroll = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if ( typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.hScroll');
}
};
})(jQuery);​
Thanks all in advance!
jQuery calls cleanData any time you do something that removes or replaces elements (yes, even if you use parent.html("") ). You can take advantage of that by extending it and having it trigger an event on the target elements.
// This is taken from https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 10/17/2012
if (!$.widget) { // prevent duplicating if jQuery ui widget is already included
var _cleanData = $.cleanData;
$.cleanData = function( elems ) {
for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
try {
$( elem ).triggerHandler( "remove" );
// http://bugs.jquery.com/ticket/8235
} catch( e ) {}
}
_cleanData( elems );
};
}
Now you can bind to the remove event when setting up your plugin and have it run your destroy method.
$(elem).bind("remove",methods.destroy)
You might use a class name and forward the resize event:
$.fn.hScroll = function(method) {
this
.addClass('hScroll')
.data('method', arguments)
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$(".hScroll").each(function(){
var method_config = $(this).data('method');
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
// Would alert "hey you" for <a class="test">you</a> on every resize
Update
If you change the dom and want to keep the selector you might try this one:
var elements = [];
$.fn.hScroll = function(method) {
elements.push({'selector' : this.selector, 'arguments' : arguments });
};
var methods['alert_text'] = function(config){
alert( config + " " + $(this).text() );
}
$(window).bind('resize.hScroll',function(){
$.each(elements,function(i, element){
$(element.selector).each(function(){
var method_config = element.arguments;
var method = method_config.shift();
// Forward the resize event with all resize event arguments:
methods[method].apply(this, method_config);
})
})
})
// Register a resize event for all a.test elements:
$("a.test").hScroll('alert_text', "hey");
$(document.body).html("<a class='test'>you</a>");
// Would alert "hey you" for every window resize
You should have the scroll event bound in the extension. Also, you will want to add a "destroy" method to your extension as well. Before you remove the element from the DOM, you will want to call this method. Inside the detroy method is where you will want to unbind the resize event.
One important thing in making this work is that you have a reference to each handler method that is bound to the resize event. Alternatively, you can unbind All resize events upon the removal on an element and then rebind the scroll event to the remaining elements that require it.

FullCalendar delete external events

When I'm trying to delete an external event from my calendar, if I add say 3 external events then drag one to the bin, rather than removing just the one event it deletes all events (even the ones from the separate feeds I am doing.
Any idea why this is and how to fix it? Here is the code:
$(document).ready(function () {
//listens for drop event
$("#calendarTrash").droppable({
tolerance: 'pointer',
drop: function (event, ui) {
var answer = confirm("Delete Event?")
if (answer) {
$('#calendar').fullCalendar('removeEvents', event.id);
}
}
});
/* initialize the external events ------------*/
$('#external-events div.external-event').each(function () {
// create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
// it doesn't need to have a start or end
var eventObject = {
title: $.trim($(this).text()) // use the element's text as the event title
};
// store the Event Object in the DOM element so we can get to it later
$(this).data('eventObject', eventObject);
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
});
The event.id in your drop function does not refer to the FullCalendar event. It refers to the drop event that was just triggered.
You will need to use ui.draggable to access your draggable - in this case the FullCalendar event.
Hope this helps! Cool concept BTW!
Update: Check this fiddle for a proof-of-concept
For anyone in the same circumstances,..
eventDragStop: function(event, jsEvent, ui, view) {
if (x) {
$('#calendar').fullCalendar('removeEvents', event._id);
}
Please notice I am using event._id, x is the result of checking which div the item is dragged into returning a true or false. checks which div the event is being dropped into. I also had to change some code in fullcalendar.js
the function eachEventElement, was causing me an issue with the above code, so I changed it too.
function eachEventElement(event, exceptElement, funcName) {
try{
var elements = eventElementsByID[event._id],
i, len = elements.length;
for (i=0; i<len; i++) {
if (!exceptElement || elements[i][0] != exceptElement[0]) {
elements[i][funcName]();
}
}
}
catch(err)
{}
}

How to get which div/ui.helper clicked in drag event jqueryui/jquery?

On Jquery UI's site:
http://jqueryui.com/demos/draggable/
If I have:
<div id="someId" class="someClass">he</div>
<div id="otherId" class="otherClass">he2</div>
And:
$('#someid','#otherid').draggable({
drag: function(event, ui) {
alert(ui.helper.THEIDOFTHECLICKEDITEM); // What goes here?
}
});
How do I get the id or class of the ID using the "ui" variable from the callback? If not possible, how do I get it from the "event" variable?
You want:
$("#someId, #otherId").draggable({
drag: function(event, ui) {
console.log(ui.helper[0].id);
}
});
(or use ui.helper.attr("id"))
Note: ui.helper is a jQuery object, which is why we must either use .attr("...") to retrieve the id or access the matched element at index 0 and directly get the id.
Or without using the ui argument (probably what I'd recommend):
$("#someId, #otherId").draggable({
drag: function(event, ui) {
console.log(this.id); // "this" is the DOM element being dragged.
}
});
Here's a working example: http://jsfiddle.net/andrewwhitaker/LkcSx/

Pass additional arguments into javascript event

I'm trying to use a JavaScript function with as an event handler for jQuery, but it needs one additional peice of information. I tried adding it on to an object with the data, and using this, but this is null when it gets executed. I believe this has something to do with function copying with in JavaScript. How can I pass my extra info.
<script type="text/javascript">
var WIDTH_ATTR = 'initWidth';
function resizeHandler(event, ui){
var change = ui.size.width - this.master.attr(WIDTH_ATTR);
this.slave.width(slave.attr(WIDTH_ATTR) - change);
};
function splitResize(master, slave, masterHandles){
var s = new SharedResize(master, slave);
master.resizable({ handles: masterHandles, resize: s.resizeHandler });
}
function SharedResize(master, slave){
this.master = master;
this.slave = slave;
this.resizeHandler = resizeHandler;
master.attr(WIDTH_ATTR, master.width());
slave.attr(WIDTH_ATTR, slave.width());
}
// initialise plugins
$(function(){
try {
$('ul.sf-menu').superfish();
splitResize($('#Content'), $('#InfoPanel'));
}catch(ex){
alert(ex.message);
}
});
</script>
This code gives an error of
Line:13
'this.master' is null or not an object.
When a resize is attempted.
Can I make this scheme work, or is there another way to associate the event handler with my data.
Try this change:
function splitResize(master, slave, masterHandles){
var s = new SharedResize(master, slave);
master.resizable({ handles: masterHandles,
resize: function(event, ui) { s.resizeHandler(event, ui); } });
}
With that, the "resize" handler will be an anonymous function that, in turn, calls your handler with the proper context (the "SharedResize" instance).
You can either do what Pointy suggested or you can do this:
function SharedResize(master, slave){
this.master = master;
this.slave = slave;
this.resizeHandler = function(event, ui){
var change = ui.size.width - this.master.attr(WIDTH_ATTR);
this.slave.width(slave.attr(WIDTH_ATTR) - change);
};
master.attr(WIDTH_ATTR, master.width());
slave.attr(WIDTH_ATTR, slave.width());
}

Categories