I'm using jquery boilerplate template for my plugin. I need to deliver some callback from this plugin. This callback need to be some variable with offsets coordinates.
var coordinates = {
x: x2, y: y2
};
I try to delegate this callback like this:
;(function ($, window, document) {
/* 'use strict'; */
// default options
var name = "plugin",
defaults = {};
// constructor
function plugin (options, callback) {
this.settings = $.extend({}, defaults, options);
this.init();
this.callback = callback;
}
plugin.prototype = {
init: function () {
var offset = $(this).offset(),
x2 = (e.pageX - offset.left),
y2 = (e.pageY - offset.top);
$(document).on('mouseup', function() {
var coordinates = {
x: x2, y: y2
};
this.callback(coordinates);
});
}
};
// initialize
$.fn[name] = function (options, callback) {
return this.each(function() {
if (!$.data(this, "plugin_" + name)) {
$.data(this, "plugin_" + name, new plugin(options, callback));
}
});
};
})(jQuery, window, document);
I have an arror that callback is not a method for this object. Can anybody help?
Focus on how and especially where you call your callback:
plugin.prototype = {
init: function () {
var offset = $(this).offset(),
x2 = (e.pageX - offset.left),
y2 = (e.pageY - offset.top);
$(document).on('mouseup', function() {
var coordinates = {
x: x2, y: y2
};
this.callback(coordinates);
});
}
};
You are creating an anonymous nested function. Anonymous functions by default have this === window
.
Edit: Thanks to KevinB's comment, I noticed that my previous statement wasn't true for all cases, simply because it is possible to change the context of functions by calling .apply()
and .call()
, which jQuery does in order to allow you to simply use $(this)
to access the element which triggered the event.
What I had in mind is that, if anonymous functions are called without these two methods, they, then this === window
. But this is also true for methods which are called directly as functions, not as methods. The following won't work either.
var obj = { foo : 'foo', bar : function(){console.log(this.foo);} };
$(document).on('mouseup', obj.bar);
First of all because of the aforementioned change of context that jQuery does when calling the callback, 2nd because of a simple rule of thumb: the context is whatever is to the left of the dot. When calling a callback like this: callback()
, nothing is to the left of the dot, i.e. this === null
(don't hit me) which doesn't exist, so it defaults to this === window
.
The fix to this is fairly easy: simply introduce a new variable that reference the instance of your plugin. This variable is commonly called that
. Minor changes should accomplish your goal:
init: function() {
var offset = $(this).offset(),
x2 = (e.pageX - offset.left),
y2 = (e.pageY - offset.top),
that = this;
$(document).on('mouseup', function(){
var coordinates = {
x: x2, y: y2
};
that.callback(coordinates);
});
}
But beware: the way your plugin currently works, it will attach a listener to the mouseup
event each time it is run. You don't need that many... especially since it will result in lags if you run the plugin a lot. I'd suggest to hook up the event listener once and call all callbacks one by one once the event has been triggered.