Reputation: 1551
I'm building a jQuery/javascript web application using jQuery .prototype
.
In the following code I want to update to prototypes global value this.score
, I'll have to bind(this)
to make this work.
Without binding this
I can reach the span inside btnElement
with $(this)
, but after binding this doesn't work anymore. Is there any workaround for something like 'this'? ;)
showQuestion: function(question) {
this.quiz.show();
var btnElement = this.quiz.find('div');
btnElement.on('click', function() {
var btn = $(this).find('span');
if (btn.hasClass('correct')) {
btn.addClass('good');
this.score += 1;
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
}.bind(this));
}
Upvotes: 0
Views: 62
Reputation: 1074158
You've bound your event callback, so this
within it refers to what this
outside it referred to. That means you can't use the usual meaning this
has within jQuery event handlers (the DOM element related to the event).
Three ways to handle that:
Use btnElement
instead, since you have it handy:
showQuestion: function(question) {
this.quiz.show();
var btnElement = this.quiz.find('div');
btnElement.on('click', function() {
var btn = btnElement.find('span'); // <====
if (btn.hasClass('correct')) {
btn.addClass('good');
this.score += 1;
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
}.bind(this));
}
Use e.currentTarget
, which is the same thing this
would have been if the handler weren't bound (in this case, you could also use e.delegateTarget
because it's not a delegated handler and so it's the same value):
showQuestion: function(question) {
this.quiz.show();
var btnElement = this.quiz.find('div');
btnElement.on('click', function(e) { // <====
var btn = $(e.currentTarget).find('span'); // <====
if (btn.hasClass('correct')) {
btn.addClass('good');
this.score += 1;
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
}.bind(this));
}
I haven't recommended e.target
because it's not quite the same thing: e.target
is the element where the event occurred; this
is the element you had the event hooked on. So e.target
may be a descendant element of your quiz's div
.
Don't bind the event handler, and instead store a reference to this
in a variable the event handler closes over:
showQuestion: function(question) {
var self = this; // <====
self.quiz.show();
var btnElement = this.quiz.find('div');
btnElement.on('click', function() {
var btn = $(this).find('span');
if (btn.hasClass('correct')) {
btn.addClass('good');
self.score += 1; // <====
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
}); // <====
}
Upvotes: 4
Reputation: 33618
One way is to NOT bind and use a reference to this
outside the click handler
showQuestion: function(question) {
this.quiz.show();
var btnElement = this.quiz.find('div');
var self = this; // create a reference to this
btnElement.on('click', function() {
var btn = $(this).find('span'); // you will still be able to find the span which is inside the btnElement
if (btn.hasClass('correct')) {
btn.addClass('good');
self.score += 1; // you will still be able to refer this which is reference as self outside
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
});
}
Other way is to send a parameter to bind
(Apart from all the other options in the other answers)
showQuestion: function(question) {
this.quiz.show();
var btnElement = this.quiz.find('div');
btnElement.on('click', function(event, btnElement) { //
var btn = btnElement.find('span');
if (btn.hasClass('correct')) {
btn.addClass('good');
this.score += 1;
} else {
$('span.correct').addClass('good');
btn.addClass('wrong');
}
}.bind(this, btnElement));
}
This works too just that it is a bit weird to send the button reference to its own click handler.
Upvotes: 2