Reputation: 640
I'm trying to write a new plugin that can be initialized on multiple elements within the same page, each time with different options, ex:
$('#id').plugin({ option:true });
$('#id2').plugin({ option:false });
I'm using the boilerplate from jqueryboilerplate.com (https://github.com/jquery-boilerplate/jquery-boilerplate). I understand (at least I think I do!) that the problem is that within the scope of the anonymous function (here, within setTimeout) 'this' refers to the window. So in the following, the output is logged the first time, but not the second:
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
console.log(this.settings.propertyName);
setTimeout(function(){
console.log(this.settings.propertyName);
}, 1000);
}
});
Elsewhere this.settings.propertyName is set to 'value'. Console.log result is:
value
Uncaught TypeError: Cannot read property 'propertyName' of undefined
If for example I set window.prop = this.settings.propertyName and console.log window.prop instead, that works, but the problem is that there may be many instances running at the same time.
I've read through lots of questions related to this subject, but none seem to actually address this particular situation. I would be grateful if someone could give me a clear example of how to do this within the context of a jQuery plugin using the boilerplate, or something like it. Please excuse my noobness, thank you!!
Upvotes: 0
Views: 180
Reputation: 87203
setTimeout
is executed as window.setTimeout
, so the context of the setTimeout
handler is set to the window
object. If you want to change the context of it, you can use bind()
.
setTimeout(function () {
// this.xyz
// use this here
}.bind(this), 1000);
The bind
will bind the context outside of setTimeout to the one inside it.
Reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
You can also cache the context and use it inside setTimeout
.
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
var self = this; // Cache context
setTimeout(function () {
console.log(self.settings.propertyName); // Use cached context instead of `this`
}, 1000);
}
});
Upvotes: 1
Reputation: 33880
It happen because the this
in the timeout refer to the window object. It can be easy fixed by keeping a reference outside the function like that :
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
console.log(this.settings.propertyName);
var self = this;
setTimeout(function(){
console.log(self.settings.propertyName); //Use your reference here.
}, 1000);
}
});
If for some reason you prefer not having a variable with the reference, you can always use Function.prototype.bind
. Be sure to check the compatibility before using it. What .bind
does is simply returning a new function while altering the this
value and the arguments. You can use it like that :
// Avoid Plugin.prototype conflicts
$.extend(Plugin.prototype, {
init: function () {
console.log(this.settings.propertyName);
setTimeout(function(){
console.log(this.settings.propertyName);
}.bind(this), 1000);
}
});
Upvotes: 1
Reputation: 11983
Capture a closure on this
:
$.extend(Plugin.prototype, {
init: function () {
var _this = this;
console.log(this.settings.propertyName);
setTimeout(function(){
console.log(_this.settings.propertyName);
}, 1000);
}
});
Upvotes: 1