This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
I have the following javascript class similar to this:
class ModalFormButton {
constructor() {
this.contactForm = new ContactForm();
let utils = new Utils();
this.$signupModal = $(utils.getModalTmpl());
}
loadContactForm() {
this.$signupModal.modal();
this.contactForm.load();
}
contactBtnHandler(e) {
e.preventDefault();
let utils = new Utils();
var $t = $(this),
$modalTitle = $t.data('modal-title'),
$modalFormId = $t.data('modal-form-id');
$('body').append(this.$signupModal);
this.$signupModal.find('.modal-title').html($modalTitle);
this.$signupModal.find('.modal-body').load($t.attr('href') + ' #' + $modalFormId,this.loadContactForm);
};
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler);
};
load() {
this.registerHandlers();
};
}
My problem is that when contactBtnHandler is called I don't have access to class properties because the context belongs to modal-form-btn.
I know I can solve this using an arrow function, but I am wondering about if its possible to separate in a function the logic in the callback (here is a short example but I have longer functions) in a way similar to the one I am using.
Thanks
You can try binding "this" to your class in your callback handler
registerHandlers() {
$('.modal-form-btn').click(this.contactBtnHandler.bind(this) );
};
One could do:
getHandler (){
return e => {
//this is ModalFormButton
};
}
And then:
$('.modal-form-btn').click(this.getHandler());
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 10 months ago.
I have the following code in my ngOnInit:
ngOnInit(): void {
let selectedArea:any = null;
let areas = document.querySelectorAll<SVGElement>('path'); // gets an array of all of the paths in the DOM
areas.forEach((area) => { // for each svg path
area.addEventListener('mouseover', function () {
area.style.fill = '#2100b6'; // add hover
});
area.addEventListener('mouseout', function () {
area.style.fill = ''; // return to default on mouse out
});
area.addEventListener('click', function () {
if (selectedArea) {
area.style.fill="black";
}
if (selectedArea !== area.id) {
selectedArea = area.id;
area.setAttribute('class', 'selectedArea'); // changed
area.style.fill="black";
}
console.log(selectedArea);
});
this.selectedRegion = selectedArea
});
}
selectedRegion : number = 0
"selectedArea" logs the selected region's code from an SVG map.
I tried to get that into the new variable "selectedRegion", but it did not work.
So, I want to use "selectedArea" outside of ngOninit, but I don't have any idea, how to do it.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
class TestClass {
constructor(word) {
this.word = word;
window.addEventListener("keypress", this.logCharCodeAndWord);
window.addEventListener("click", this.logWord)
}
logCharCodeAndWord(e) {
console.log(e.charCode);
console.log(this.word)
}
logWord() {
console.log(this.word)
}
}
var testObject = new TestClass("banana");
I don't even know how to ask this question, but here's my problem...
console.log(this.word)
This logs "undefined" to the console, because this refers to window instead of the TestClass. I want this.word to refer to "banana", and I would like to be able to use the e.charCode part at the same time.
How would I do that?
You need to either pass in the this of your class object:
window.addEventListener("click", this.logWord.bind(this))
Or you can use an arrow-function:
window.addEventListener("click", () => this.logWord())
Simply pass this to your event listeners.
window.addEventListener("keypress", e => this.logCharCodeAndWord(e, this));
window.addEventListener("click", () => this.logWord(this));
class TestClass {
constructor(word) {
this.word = word;
window.addEventListener("keypress", e => this.logCharCodeAndWord(e, this));
window.addEventListener("click", () => this.logWord(this));
}
logCharCodeAndWord(e, self) {
console.log(e.charCode);
console.log(self.word)
}
logWord(self) {
console.log(self.word)
}
}
var testObject = new TestClass("banana");
This question already has answers here:
JQuery nested this references [duplicate]
(4 answers)
Closed 7 years ago.
Here's my nested usage of .each:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
$("[id^='item-tipo-']").each(function() {
itemData["segmentos"][$(outerthis).val()] = $(innerthis).val();
});
});
How can I use the "outerthis" within the scope of the inner .each?
To use the 'outer' this in the inner each() loops, you simply have to cache the 'outer' this in a variable, and then refer to that variable in place of using this within the inner each() loops:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
var outerThis = $(this);
$("[id^='item-tipo-']").each(function() {
var innerThis = $(this);
itemData["segmentos"][outerThis.val()] = innerThis.val();
});
});
You can assign it to a variable in the outer function. This will form a closure and the inner function will have access to the outer variable:
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function() {
var outerthis = this;
$("[id^='item-tipo-']").each(function() {
itemData["segmentos"][$(outerthis).val()] = $(this).val();
});
});
But note that jQuery passes the index and element as parameters to your callback, which can make for clearer code, e.g.
itemData["segmentos"] = {};
$("[id^='item-segmentos-']").each(function(oIndex, outerElement) {
$("[id^='item-tipo-']").each(function(iIndex, innerElement) {
itemData["segmentos"][$(outerElement).val()] = $(innerElement).val();
});
});
This question already has answers here:
JavaScript - Owner of "this"
(6 answers)
Closed 8 years ago.
I have this function right here which takes the parts of my object and illuminates them successively with a delay (it switches the opacity of an element to 1 and then switches the previous element opacity to 0 to illuminate them successively).
The problem is that I cannot use the this keyword to access the parent objects parts in the illuminateInternal function.
This hinders any possible reuse of my object since I will have maleBackNoZoom and maleBackFullZoom objects.
I don't want to change the variable names of the illuminateInternal function when I re-use my object so I would like to use something like the this keyword in the illuminateInternal function as well.
maleBackNoZoom = {
parts:{
armsRight: findItemById("29") ,
armsLeft: findItemById("28"),
legsRight: findItemById("21"),
legsLeft: findItemById("22"),
back: findItemById("24"),
buttocks: findItemById("23"),
neck: findItemById("26"),
head: findItemById("27")
},
illuminate: function() {
var propertiesToIlluminate = [], prop, illuminateInternal, i = 0, delay = 200, intervalId;
for (prop in this.parts) {
propertiesToIlluminate.push(prop);
}
illuminateInternal = function () {
var property = propertiesToIlluminate[i];
var previousProperty = propertiesToIlluminate[i-1];
maleBackNoZoom.parts[property].opacity = 1;
console.log(previousProperty);
if (typeof previousProperty !== 'undefined'){
maleBackNoZoom.parts[previousProperty].opacity = 0;
}
paper.view.update();
i++;
if (i === propertiesToIlluminate.length) {
maleBackNoZoom.parts[property].opacity = 0;
clearInterval(intervalId);
setInterval(function(){paper.view.update()},delay);
}
};
intervalId = setInterval(illuminateInternal, delay);
}
}
You can define local variable inside illuminate method which will store reference to its object. And then you can use it as alias of this.
var self = this;
illuminateInternal = function () {
..
self.parts[property].opacity = 1;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript Closure Problem
In the following code, TrueThis.aChoices[i]['CallBack'] is a function when the click event is created and "false" when the click event actually occurs. How do I get the function reference into the click event handler?
My Object:
ATK.MultiChoiceDialog = function() {
var TrueThis = this;
var aChoices;
this.Show = function(sTitle,sPrompt,aChoices){
this.aChoices = aChoices;
var HTML = '[snip]';
$('body').append(HTML);
for(var i in this.aChoices)
{
console.log(TrueThis.aChoices[i]['CallBack']); // shows "function"
$('#ATKDialogButton'+i).click(function(e){
console.log(TrueThis.aChoices[i]['CallBack']); // shows "false" ???
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(aChoices[i]['Context']);
}
});
}
}
};
I've also tried this:
for(var i in this.aChoices)
{
var CB = TrueThis.aChoices[i]['CallBack'];
console.log(CB); // function
$('#ATKDialogButton'+i).click(function(e){
console.log(CB); // false
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(aChoices[i]['Context']);
}
});
}
jQuery has a built-in way of handling this by passing event data to the callback function being bound to the event.
ATK.MultiChoiceDialog = function() {
var TrueThis = this;
var aChoices;
this.Show = function(sTitle,sPrompt,aChoices){
this.aChoices = aChoices;
var HTML = '[snip]';
$('body').append(HTML);
for(var i in this.aChoices){ // in js the '{' should be on same line
console.log(TrueThis.aChoices[i]['CallBack']); // shows "function"
$('#ATKDialogButton'+i).click({i:i},function(e){ // data passed in with {i:i}
console.log(TrueThis.aChoices[e.data.i]['CallBack']); // shows "function"
if(TrueThis.aChoices[e.data.i]['CallBack']){ // in js the '{' should be on same line
TrueThis.aChoices[e.data.i]['CallBack'].call(aChoices[e.data.i]['Context']);
}
});
}
}
};
Thanks to the comments, I've got this working. First create a new function to "fix" the value of i, which returns the function for the event handler.
this.FixI = function (i){
return function(e){
if(TrueThis.aChoices[i]['CallBack'])
{
TrueThis.aChoices[i]['CallBack'].call(TrueThis.aChoices[i]['Context']);
}
}
}
Use the new function to generate the even handlers function in the loop:
for(var i in this.aChoices)
{
$('#ATKDialogButton'+i).click(TrueThis.FixI(i));
}
UPDATE: It looks like Kevin B found a Jquery way of addressing the problem that doesn't require an extra "preserver" function.