This question already has answers here:
"this" keyword in event methods when using JavaScript prototype object
(4 answers)
Closed 3 years ago.
Im making a program that dynamically creates html elements and when you click any of those elements it should display its value in another textbox. This is the class im using to define the element:
class msg_element{
constructor(msg){
this.message = msg;
this.element = document.createElement("P");
this.element.innerHTML = this.message;
this.element.addEventListener("click", function(){
document.getElementById("update").value = this.message;
});
document.getElementById("textview").appendChild(this.element);
}
}
and this is the loop that creates the elements:
for(var i = 0; i < bmg_msg.length; i++){
var element = new msg_element(bmg_msg[i]);
}
it creates all the elements correctly, but the clicking function doesnt work, it just displays "undefined" in the textbox. What can I do to fix this?
The line
this.element.addEventListener("click", function(){
document.getElementById("update").value = this.message;
});
is the problem.
When you create the callback you define it as function(){...}. The problem with that is that it causes this to refer to the event target. To fix this you can either:
Use an Arrow function so that this will refer to the current class instance.
this.element.addEventListener("click", ()=>{
document.getElementById("update").value = this.message;
});
or create a variable to store the reference to the constructor
let _this = this;
this.element.addEventListener("click", function(){
document.getElementById("update").value = _this.message;
});
In this portion of your code:
this.element.addEventListener("click", function(){
document.getElementById("update").value = this.message;
});
Beware: this outside of the click handler is different from this inside of it.
Inside event handlers, this always points to the DOM element that fired the event (in your case it's the paragraph you're creating).
A possible fix would be to use a variable which will hold the value of this.message, e.g.:
var myMessage = this.message;
this.element.addEventListener("click", function(){
document.getElementById("update").value = myMessage;
});
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I need to bind a Blur event into a Method with JS, and retrieve the object data. That's what I got:
class TestClass {
constructor(input) {
this.inputTest = input;
this.objectTest = {
1: "one",
2: "two",
3: "three"
}
this.isBinded = false;
}
test() {
if(!this.isBinded) {
this.inputTest.addEventListener("blur", function( event ) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(this.objectTest);
});
}
this.isBinded = true;
}
}
var test = new TestClass(document.querySelector("input"));
test.test();
So, this is a simple example of what I need. I have one input, and when I initialize the class, I bind a blur event. When I try it, it just shows me the alert, so apparently looks to work.
However, it seems it cannot access into the object scope, because it doesn't return me the this.objectTest object example from the object scope.
Can anyone help me? Thanks
Because you're using a regular function in the addEventListener it is rebinding this to the inputTest element. You need to use an arrow function to keep this as your class object. Like this:
this.inputTest.addEventListener("blur", ( event ) => {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(this.objectTest);
});
However, it seems it cannot access into the object scope, because it doesn't return me the this.objectTest object example from the object scope
Yes, indeed inside the addEventListener callback, this refers to the input that you are attaching the event to, so this.objectTest will be undefined, as it's not referring your class's objectTest property.
What you need to do is to make a reference to your class this, so you can access it inside the callback, you can assign it to another variable like this:
test() {
var _self = this;
if(!this.isBinded) {
this.inputTest.addEventListener("blur", function( event ) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(_self.objectTest);
});
}
this.isBinded = true;
}
Demo:
Here's a Demo showing how it works.
class TestClass {
constructor(input) {
this.inputTest = input;
this.objectTest = {
1: "one",
2: "two",
3: "three"
}
this.isBinded = false;
}
test() {
var _self = this;
if (!this.isBinded) {
this.inputTest.addEventListener("blur", function(event) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(_self.objectTest);
});
}
this.isBinded = true;
}
}
var test = new TestClass(document.getElementById("js-test"));
test.test();
Check it : <input id="js-test" />
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I am trying to call a function via this reference inside of jquery scope:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on('click', function(){
this.hello();
});
}
}
Then I do:
var p = new Person();
When I click over the .jump element, the console prints an error describing that hello is not a function. I am not sure what is happening here, I am assumming that this is trying to call a function inside of jquery (not sure about it).
So, googling a little bit I found the Jquery.proxy() function that could be helpfull in my situation, but every time I try to understand it my head want to explote.
Use $.proxy() like so:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on(
'click',
$.proxy(
function() {
this.hello();
},
this
)
);
}
}
Passing this as the 2nd argument to $.proxy() sends that context as the value of this inside the function defined in the first argument.
Try this,
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}
when you refer to "this" inside onclick, by default this refers to the DOM element found in the value of event.target
$('.jump').on('click', function(event) {
this.hello() /// <<-- this == event.target =~ $('.jump')
}
so, fortunately, you can use a closure
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}
I have the following code:
for(var i = 0; i < nodelist.length; i++) {
var x = functionThatCreatesADivElement();
someElement.appendChild(x.getDiv()); // this works fine
nodelist[i].onclick = function() {
x.someFunction(); // this always refer to the last 'x' object
}
}
function functionThatCreatesADivElement() {
var div = document.createElement("div");
this.someFunction = function() {}
this.getDiv = function() {
return div;
}
return this;
}
the problem is that the execution of nodelist[0].onclick is exactly the same as nodelist[4].onclick (assuming that i = 4 is the last node).
I believe the references of the previously iterated are changing to point to the currently iterated element.
What is the proper way of doing this?
EDIT: Added some more code and changed the name of the function cause it was too confusing
You have two problems. The first problem is that JavaScript variables don't have block scopes.
From MDN:
When you declare a variable outside of any function, it is called a global variable, because it is available to any other code in the current document. When you declare a variable
within a function, it is called a local variable, because it is available only within that
function.
JavaScript does not have block statement scope;
You aren't enclosing a the x variable in a function, so all of your onclick callbacks are using the same x variable, which point to whatever element is last in the loop since that will be the last one to have overwritten x.
Doing this for your loop should work:
nodelist.forEach(function (nodeitem) {
var x = functionThatCreatesADivElement();
someElement.appendChild(x.getDiv());
nodeitem.onclick = function() {
x.someFunction();
}
});
The second problem is that your functionThatCreatesADivElement() constructor function is not being called correctly. Use new functionThatCreatesADivElement() since you are invoking a constructor function.
Solved. I had to use
var x = new functionThatCreatesADivElement();
function functionThatCreatesADivElement() {
var div = document.createElement("div");
this.someFunction = function() {}
this.getDiv = function() {
return div;
}
//return this; //Using new instead of returning this
}
This question already has answers here:
jquery using this to access object context when inside callback
(3 answers)
Closed 8 years ago.
I have a class Playlist :
function Playlist() {
this.episodes = [ /*episode list*/ ];
};
and I want to make a method displaying each episode :
Playlist.prototype.display = function() {
$('.episodeList').each(function(index) {
$(this).children('title').text(this.episodes[index].title);
});
}
The problem is that the 'this' at the end, before '.episodes[index]' represent the dom object selected and not my playlist.
How can I solve this problem ? Thanks.
Bind the function to your context:
$('.episodeList').each($.proxy(function(index, elem) {
$(elem).children('title').text(this.episodes[index].title);
}, this));
More on jQuery.proxy
If you use each on dom element, this inside each have reference to dom elements
For example:
Playlist.prototype.display = function(e)
{
$('.episodeList').each(function(index) {
console.log(this)
});
}
console.log prints dom element and it is correct.
Now put console log outside each like this:
Playlist.prototype.display = function(e)
{
console.log(this)
$('.episodeList').each(function(index) {
});
}
Now console.log should print PlayList function (your class). So "this" in each scope have reference to dom elements but this in Playlist.prototype.display scope have reference to Playlist function.
Solution is:
Playlist.prototype.display = function(e)
{
var self = this;
$('.episodeList').each(function(index) {
console.log(self)
console.log(this)
});
}
You need take "this" from Playlist scope and attribute to self var, so now self have refenrece to Playlist. Now you do each, so current this in each have reference to dom element but self variable still have reference to Playlist.
In your code $(this)=episodes[index] because it's in the each function. I think this is what you want,
Playlist.prototype.display = function() {
var element=$(this);
$('.episodeList').each(function(index,item) {
item.children('title').text(element.episodes[index].title);
});
}
A common practice in Javascript is to make a new variable for storing the current class, since the content of the this variable changes with context. Consider something like
function Playlist()
{
var self = this;
this.episodes = [/*episode list*/];
this.display = function()
{
$('.episodeList').each(function(index) {
$(this).children('title').text(self.episodes[index].title);
});
}
};
for your Playlist class definition, and call myPlaylist.display()
to display the content.
I have a class that creates an anchor object. When the user clicks on the anchor I want it to run a function from the parent class.
function n()
{
var make = function()
{
...
var a = document.createElement('a');
a.innerHTML = 'Add';
//this next line does not work, it returns the error:
//"this.add_button is not a function"
a.onclick = function() { this.add_button(); }
...
}
var add_button = function()
{
...
}
}
How can I get this done?
Looks like you just need to get rid of the "this." in front of add_button()
You are declaring add_button as a local variable (or private in the weird way that javascript classes work), so it isn't actually a member of "this".
Just use:
a.onclick = function(){add_button();}
The reason it's not working is that this in the context of the onclick function is not the same as this in the context of the n function/"class". If you want this within the function to be equivalent to this from the class, you need to bind this to the function.
Binding is a way of changing the scope of a function -- essentially if you bind to a function, you are replacing the this variable to point to something else. You can read more about binding in Javascript in this alternateidea article.
If you were using prototype, for example, you could do something like:
function n()
{
var make = function()
{
...
a.onclick = function() { this.add_button() }.bind(this);
...
}
}
Which would bind class n's this to the onclick function, thus giving the effect you want.
The "this" in "this.add_button();" is actually referring to the anchor element itself which has no "add_button()" function, if I'm not mistaken.
Perhaps this would work:
a.onclick = function() { n.add_button(); }