This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
I've created a class and I'm trying to call a method from inside that class from another method inside that same class. I've seen online that some people say use 'this' keyword, but as you can see from the example, that doesn't work. Can someone please explain in simple terms how to call a class method from inside another method in that same class? Thanks!
class Form {
constructor() {
}
fn1 () {
console.log('fn1 calling fn2 now:')
this.fn2();
}
fn2 () {
console.log('fn1 called me')
}
}
let myForm = new Form();
myForm.fn1();
Example can be found here
The error I keep getting is this: Uncaught TypeError: this.fn2 is not a function
There's nothing wrong with the code you show embedded into your question - that should work just fine. The issue arises when you pass a method to .addEventListener() as a callback (which shows in the code you have a link to).
Change this:
document.getElementById('call-func').addEventListener('click', this.fn1);
to this:
document.getElementById('call-func').addEventListener('click', this.fn1.bind(this));
The problem is that passing this.fn1 loses the value of this so when the listener calls the callback later, the object that it belongs to is lost and then this inside of fn1() is wrong. In addition, .addEventListener() explicitly sets the this value to the DOM element that triggered the event (which is not your object).
The same thing would happen if you did this:
let f = this.fn1;
f();
Using .bind(this) rebinds the value of this when the listener calls it.
FYI, you could also do it this way with a fat-arrow function:
document.getElementById('call-func').addEventListener('click', () => this.fn1());
Or, an older way of doing it:
var self = this;
document.getElementById('call-func').addEventListener('click', function() {
self.fn1();
});
My preference is to use .bind(this).
More explanation on event listeners and this here: "This" within es6 class method
More explanation on the general concept of how this gets set when a function is called here: When you pass 'this' as an argument
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
I know this may seems silly but I'm a beginner and I just need to make sure that I understand it well:
In JavaScript when I define an event listener, the callback function is called without () to prevent immediate execution, like the below example:
document.querySelector('#button').addEventListener('click',eventHandler)
function eventHandler() {
alert('clicked')}
my confusion is if implemented the above in a class and defined the eventHandler callback function as a method, I have to use () when I call it, like the below example:
class home {
constructor(){
this.button = document.querySelector('#button')
this.clickEvent()
}
//events
clickEvent(){
//here i have to use eventHandler() not eventHandler
this.button.addEventListener('click',()=>this.eventHandler())
}
//method
eventHandler(){
alert('clicked')
}
}
new home()
In code snippet with class, you are passing a function to addEventListener function which then calls the eventHandler function.
() => this.eventHandler() is an arrow function which executes this.eventHandler() inside its body
if you remove the arrow function then you will have to pass the name of the function instead of calling it
this.button.addEventListener('click', this.eventHandler)
Edit:
keep in mind that if the eventHandler method uses this, then you may run into problems because of how value of this is set in different cases.
Currently, eventHandler function isn't using this but you should read how to access correct this inside callbacks.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
Recently, I've come across this problem where I had two methods in a class. One was referring to another but the other wasn't being recognized even though I could execute them individually.
class ButtonProcessor {
buttonClick() {
this.otherMethod();
}
otherMethod() {
console.log("This does not work!");
}
}
var buttonProcessor = ButtonProcessor;
document.getElementById("button").onclick = buttonProcessor.buttonClick;
The first method was called from a button click which was associated with a callback to that method.
One solution I found for this is to make the method that is called by the button a seperate function from the class and make it reference a class object that was already being used else-where. This is because apparently, when a method is referenced in a callback, using this to refer to another method doesn't work, because the callback only considers that one method.
class ButtonProcessor {
otherMethod() {
console.log("This does work!");
}
}
var buttonProcessor = ButtonProcessor;
function buttonClick() {
buttonProcessor.otherMethod();
}
document.getElementById("button").onclick = buttonProcessor.buttonClick;
Could there be another way to fix this?
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 3 years ago.
I was hoping to be able to call object methods from an event listener, however, I am unable to access object properties on the called function:
import {action} from '../desktopIntegration/actions.js'
class Object {
constructor() {
this.property = 2
}
addListener() {
action.on("keyup", this.printEvent)
}
printEvent() {
console.log(this.property)
}
}
This code gives the error:
unable to access property of undefined
when addListener is called.
Is there a way to make this work? I want to keep the callback as a method function so that I can delete the listener on each instance of Object.
Thanks!
Instance methods are not bound to the class instance by default. If a method is being used as an event listener, it is by default bound to the element emitting the event.
To fix that, you need to overwrite your method in the constructor, by a version bound to the class instance:
class Foo {
constructor() {
this.property = 2
this.printEvent = this.printEvent.bind(this)
this.addListener()
}
addListener() {
document.getElementById('action').addEventListener("keyup", this.printEvent)
}
printEvent(event) { // added the event argument, gets automatically passed to the listener
console.log(this.property)
console.log(event.target.value) // to access the event emitting element, use event.target
}
}
const bar = new Foo();
<input id="action" />
Also note that you should NEVER call your class Object.
Here is the app I'm referring to:
I am trying to fundamentally understand the bind method in Javascript.
My understanding when I play around with it in the console is that bind returns a copy of the function, with "this" bound to whatever you pass into bind.
function logThis(){
console.log(this)
}
logThis.bind({today: 'Tuesday'})
//Will return a copy of the logThis function, with 'this' set to the
{today:'Tuesday'} object. The code does not run right away though.
var explicitlyLogThis = logThis.bind({today: 'Tuesday'});
explicitlyLogThis(); //This will run the code and display the {today: 'Tuesday'} object to the console.
This is my understanding so far. I understand that to actually run this new function that has 'this' explicitly bound using the bind method, you need to set it to a variable and then run it.
I see a contradiction when I look at the app in the above link. If you look at the bindEvents method on line 56, we have .on('keyup', this.create.bind(this)). I understand that we have to set 'this' to App when we run the create method because jQuery defaults to setting 'this' to the jQuery object itself. So this line is actually the same as: $('#new-todo').on('keyup', App.create.bind(App)).
That isn't where my confusion is. My question is:
How exactly are these copies of the functions with 'this' set to App actually being called? The app does not set them to a variable and then call that variable the way I had to when I was working in the console.
It just invokes the bound functions directly as soon as an event occurs on one of the jQuery elements. But I thought writing it this way would just return a copy of the function, and not run the function itself, if I am basing my assumptions on what I have figured out in the code I wrote above. I thought in order to invoke the function immediately, you would need to use call or apply.
I also realize that the app runs the bindEvents method when it starts (see line 46). So I understand that when you start the app, copies of the various functions are created with the correct 'this' bound to the functions. But...when/how do they actually get invoked without assigning them to variables? How are these copies accessed?
I think I have a flawed understanding of the bind method, so I would love some help. Thanks!
It sounds like you understand bind well enough. Perhaps there is some confusion with passing anonymous functions. As you know calling bind returns a new function and this can optionally be stored as a variable or passed as a function argument.
In the example below btn1 accepts a bound function as you've seen. This could also be written in a more long hand fashion with btn2. They're identical. btn3 doesn't receive a bound function, when its clicked its context is the button element, this looses all visibility of MagicalApp fucntions.
<button id="example1">button one bound</button>
<button id="example2">button one bound</button>
<button id="example3">button two unbound</button>
<script>
class MagicalApp {
add() {
console.log('this could do addition');
}
}
const app = new MagicalApp();
function contextOfEvent(event) {
console.log('contextSensitive', this.add)
}
const btn1 = document.querySelector("#example1");
btn1.addEventListener('click', contextOfEvent.bind(app));
const btn2 = document.querySelector("#example2");
const btn2ClickHandler = contextOfEvent.bind(app)
btn2.addEventListener('click', btn2ClickHandler);
const btn3 = document.querySelector("#example3");
btn3.addEventListener('click', contextOfEvent);
</script>
This question already has answers here:
onClick handler is triggered on each render cycle
(4 answers)
Closed 4 years ago.
Could someone please explain to me why when i am trying to bind onClick action to element it works good until i dont add brackets to pass arguments to function?
getUser(id) {
console.log(id);
}
renderResults(){
if (typeof this.props.results[0] == 'undefined') {
return null;
} else {
var results = this.props.results[0].payload;
var formatedResults = results.map((singleResult) => {
return (
<div className="col-md-4 single-result" key={singleResult.account_id} onClick={this.getUser(singleResult.id)}>
<div>{singleResult.nickname}</div>
</div>
)
});
return formatedResults;
}
}
that code works on load instead of on click and returns x console logs just when page is loaded not when i click element, but when i remove brackets and i am console logging static text in getUser function it works good.
Any help or helpful links? Thanks
onClick={(e) => this.getUser(singleResult.id)}
doc : https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers
We have different ways to bind events to your DOM elements in react.
One of the most commonly used way is using 'bind'
Another is using arrow functions.
Using public class fields syntax
In your scenario, you are calling your function directly by doing this.getUser(singleResult.id). This executes the method rather than binding it to your DOM element.
Try changing it to this.getUser.bind(this, singleResult.id) which should be passing your singleResult.id to your method.
Another way to do it is using arrow functions like onClick={(e) => this.getUser(singleResult.id)}
But be careful while using arrow functions because there are chances of unnecessary rendering of components in some scenarios.
Please make sure to take a look at the documentation to give more details on events handing in react
use constructor to bind the function. use inside your component. and all your codes as it is
constructor(props) {
this.getUser = this.getUser.bind(this);
}
It's because you're calling the function, instead of passing it to onclick.
You can bind the value to the function, with an arrow function, if you're not passing anything, then it will keep its state:
getUser = () => {
console.log(this);
}
onClick={this.getUser}
or in your case pass the function to the onclick:
onClick={(e) => this.getUser(singleResult.id)}
You can read all about it here