Access THIS inside Jquery listener [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I'm trying to achieve the task shown by the example code below, but get this error :
Uncaught TypeError: this.myFunction is not a function
I know i'm doing something wrong but don't know the right way to do it : how can i access the 'this' object inside a Jquery listener ?
Thanks in advance !
var MyClass = function () {
return {
myFunction: function () {
console.log('Do something');
},
myOtherFunction: function() {
$('#myButton').on('click', function () {
this.myFunction(); // here i get the error
});
}
}
}

You can use arrow function, it takes care of auto binding and you can stay away with scope related issues
ES6:
var MyClass = () => {
return {
myFunction: () => {
console.log('Do something');
},
myOtherFunction: () => {
$('#myButton').on('click', () => {
this.myFunction(); // this will be available here
});
}
}
}

Related

Can't understand the context: got undefined while it shouldn't be [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
I need to remove some popup element from the page with a click on the button, but something is happening to the context or to the property of the object and I have absolutely no idea what is going on.
constructor(container) {
this._container = container;
this._card = null;
this._popup = null;
}
render(card) {
this._card = new Card(card);
renderComponent(this._container, this._card);
this._card.clickCardListener(".film-card__title", "click", function () {
this._popup = new Popup(card);
console.log(this._popup);
**//log: Popup {_element: null, _card {...}**
renderComponent(mainElement, this._popup);
console.log(this._popup);
**//log: Popup {_element: section.film-details, _card {...}**
this._popup
.getElement()
.querySelector(".film-details__close-btn")
.addEventListener("click", function () {
console.log(this._popup);
**//log: undefined**
});
});
}
All this worked before I've tried to use a controller (I am studying OOP, so it goes...) Please, help. I've already spent about 5 hours on this line code and i have no idea what am i doing
Try with this
this._popup
.getElement()
.querySelector(".film-details__close-btn")
.addEventListener("click", () => {
console.log(this._popup);
});
or
var self = this;
this._popup
.getElement()
.querySelector(".film-details__close-btn")
.addEventListener("click", function() {
console.log(self._popup);
});
You have to pass the arrow function as the second argument of .addEventListener method because it has no own context and takes the parent context.
this._popup
.getElement()
.querySelector(".film-details__close-btn")
.addEventListener("click", () => {
console.log(this._popup);
});
Here you can read more about a function's this keyword.

use variable of 'this' in setInterval [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
hi I want to use 'this' variable in setInterval in a jquery function
I write '// this code don't work' after don't worked line
(function($)
{
$.fn.rotate=function () {
var counter=0;
var timer=setInterval(function () {
counter++;
var transform='rotate('+counter+'deg)';
$(this).css('transform',transform); // this code dont work
if(counter>=300)
clearInterval(timer);
},1);
return this;
};
$('#socialNetworks i').rotate();
}(jQuery))
thanks Alot
Using the arrow function when defining the function maintains the this context in which the function has been called. Thus you would be able to access this inside the function correctly.
( $ => {
$.fn.rotate=function () {
var counter=0;
var timer=setInterval(function () {
counter++;
var transform='rotate('+counter+'deg)';
$(this).css('transform',transform); // this code dont work
if(counter>=300)
clearInterval(timer);
},1);
return this;
};
$('#socialNetworks i').rotate();
})(jQuery)

Strange Function Behavior with Prototype and Event Listeners - JavaScript [duplicate]

This question already has answers here:
The value of "this" within the handler using addEventListener
(10 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
Original Modal
I want to use a universal app object. To this empty object I will add functions as needed. The issue is that some functions will need to all others within the app object.
So, my question is: how do I construct a large object without having to define all functions inside the object at the time of creation? I would like to split up the chunks of code to not have one astronomical long .js file.
There is a simple example of my original code:
var app = {
tow: function () {
return true;
},
one: function () {
return this.tow();
}
};
// app.one() => returns true
Updated Modal
Here is something I found interesting. I was playing around with the prototype modal and discovered something strange. When I use this model I can add functions that can call other added functions. But, when I create an event listener it is unable to run the code. Can anyone explain why this is?
Modified code with unexpected result:
function modal () {}
modal.prototype.one = function () {
return this.two();
};
modal.prototype.two = function () {
return "cool";
};
modal.prototype.init = function () {
document.getElementById('go')
.addEventListener("click", this.one);
}
var app = new modal();
app.init();
// app.one() => returns true
// event listener => returns "TypeError: this.two is not a function"
JSBIN: https://jsbin.com/vureruziza/edit?js,console,output
this.one called as you done refers to addEventListener function, not to your object. This will solve the issue
modal.prototype.init = function () {
var self = this;
document.getElementById('go')
.addEventListener("click", function(){
self.one()
});
}
bind the click function with this cause the function will need the this context, not the window context. Then call your this.one function in de click handler.
function modal () {}
modal.prototype.one = function () {
return this.two();
};
modal.prototype.two = function () {
return "cool";
};
modal.prototype.init = function () {
document.getElementById('go')
.addEventListener("click", function(e){
console.log(this.one())
}.bind(this));
/*
The following wil also be called but your return value
of your this.one function won't be captured. But your code will run.
.addEventListener("click", this.one.bind(this));
Try replacing it with the above and put a debugger statement in this.one
and see that the code will actualy be ran, just not captured to output.
*/
}
var app = new modal();
app.init();
// app.one() => returns true
// event listener => returns "TypeError: this.two is not a function"
<div id="go">go</div>
Use ES6 fat arrow function. Update modal.prototype.init as below -
modal.prototype.init = function () {
document.getElementById('go')
.addEventListener("click", () => this.one());
}
Edit - If you wanted to debug the issue, you could just console.log the this value in function one like so -
modal.prototype.one = function () {
console.log(this);
return this.two();
};
You will most likely see the window object. You will certainly not see the modal object.

"this" return undefined in a prototype function [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I want to run multiples asynchronous task with async package.
But I have issues with javascript prototypes access.
Here's the sample of my code:
var env = function(options) {
this.options = options;
}
env.prototype.run = function() {
var self = this,
async.series([
self.task1,
self.task2
], function done(responses) {
console.log(responses);
});
}
env.prototype.task1 = function() {
console.log(this.options); // undefined
// logic code...
}
var foo = new env({foo: 'bar'});
foo.run(); // undefined - from console.log
Don't know why I can't access the 'this' properties of my Object
This code
async.series([
self.task1,
self.task2
], function done(responses) {
console.log(responses);
});
just passes function references into async.series, but does nothing to ensure that this is correct when they're called.
Unless the async.series you're using offers a way to tell it what this to use, you can readily solve the problem with bind:
async.series([
self.task1.bind(self), // ***
self.task2.bind(self) // ***
], function done(responses) {
console.log(responses);
});
Here's a simpler example demonstrating the problem and solution:
var obj = {
property: "testing",
wrong: function() {
setTimeout(this.task1, 10);
},
right: function() {
setTimeout(this.task1.bind(this), 20);
},
task1: function() {
console.log("task1 says the property is " + this.property);
}
};
obj.wrong();
obj.right();
Side note: Unless you're using self for something you haven't shown inside run, you don't need it at all:
env.prototype.run = function() {
async.series([
this.task1.bind(this),
this.task2.bind(this)
], function done(responses) {
console.log(responses);
});
};
Another option if you're using an ES2015-compatible environment (or transpiling) is to wrap your tasks in arrow functions:
// Requres ES2015 support
env.prototype.run = function() {
async.series([
(...args) => this.task1(...args),
(...args) => this.task2(...args)
], function done(responses) {
console.log(responses);
});
};

How do you add objects to a javascript namespace?

var Test = (function() {
return {
useSub: function () {
this.Sub.sayHi();
},
init: function () {
$(document).ready(this.useSub);
}
};
})();
Test.Sub = (function () {
return {
sayHi: function () {
alert('hi');
}
};
})();
Test.useSub(); // works
Test.init(); // explodes
Above I am trying to create a Test namespace and add an object Sub to it. I was doing fine until I tried using the object in jQuery. The error is "Uncaught TypeError: Cannot call method 'sayHi' of undefined". If there is a better way to do this, I am open to it.
Edit:
Obviously this was demo code. In my real application the solution that I went with because I think it is the most clear is this one:
var Namespace (function () {
return {
init: function () {
$(document).ready(function() {
Namespace.onReady();
}
},
onReady: function() {
alert('Now I am back in the Namespace scope. Proceed as planned');
}
};
})();
Edit2: All jQuery callbacks seem to require they are used in this manner or else the scoping is screwed up.
I think it is a scope problem. If you do
$(document).ready(this.useSub);
then this.useSub will be executed in the window scope (so inside the function, this refers to the window object) and there doesn't exist a Sub attribute.
Try:
init: function () {
var obj = this;
$(function(){obj.useSub()});
}
For some reason it does not work using $(document).ready(function(){obj.useSub()}); but it works with the $() shortcut.
Here is one way
var Test = {
useSub : function () {
Test.Sub.sayHi();
},
init: function () {
$(document).ready(Test.useSub);
},
Sub: {
sayHi: function () {
alert('hi');
}
}
};
in this line:
$(document).ready(this.useSub);
you're passing a reference to a function and the scope is lost- when the function runs, this no longer means Test.

Categories