I have a function with parameter that is pass as a property:
currentTaskID = null;
setTaskID = (id) => {
this.currentTaskID = id;
console.log(this.currentTaskID);
console.log("test");
}
Then on my other component I have a function that needs the event handler and call the prop function when clicked:
// select/open task
openTask = (event) => {
let targetClass = event.target.classList;
if(targetClass.contains('active'))
targetClass.remove('active')
else
targetClass.add('active')
}
// onClick trigger multiple functions
funcWrapper = (id) => {
this.openTask();
this.props.setTaskID.bind(this, id)
}
Onclick:
onClick={funcWrapper(id)}
error:
Cannot read property 'target' of undefined
How can I pass parameters without overwriting the event?
As the error suggested Cannot read property 'target' of undefined. It is not able to find the target property in undefined. Because target is a property of event object. Because event has not been passed to the method it is represented with undefined.
I suppose you have to do the call in a anonymous callback:
onClick={e => funcWrapper(e, id)}
Then pass the event to the method:
funcWrapper = (ev, id) => {
this.openTask(ev);
this.props.setTaskID(id); // <---as it is in fat arrow syntax no need for bind
}
Related
I use a loop through the node elements to get the ID from the clicked element. Until then all good and it works. Now I want to call an another function in my class & get this error:
this._PreLoad is not defined at HTMLElement.s.onclick
this._joinnews.forEach((node) => {
node.onclick = function(){
const requestData = `newsid=${node.id}`;
// some code //
this._PreLoad(true); // ERROR
// _PreLoad(true); not working
// this._PreLoad(true).bind(this); not working (I am not yet familiar with the bind function)
}
});
Are the functions inside a node loop unknown ?
The correct place to bind this is here:
node.onclick = function() {
const requestData = `newsid=${node.id}`;
// some code //
this._PreLoad(true);
}.bind(this); // bind here!
Alternatively, use an arrow function which preserves this as whatever it was at the time of the function declaration:
node.onclick = () => {
const requestData = `newsid=${node.id}`;
// some code //
this._PreLoad(true);
}
This question already has answers here:
What does "this" refer to in arrow functions in ES6?
(10 answers)
Closed 6 years ago.
I'm going through the JavaScript30 challenge, and in lesson 3 he's got some event listener calling a function that references the element it's called on as this:
const inputs = document.querySelectorAll('.controls input');
function handleUpdate() {
const suffix = this.dataset.sizing || '';
document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
}
inputs.forEach(input => input.addEventListener('change', handleUpdate));
inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));
I'm trying to rewrite it with ES6 arrow function, but I can't get the this to work right. I got a workaround using target:
const handleUpdate = (e) => {
const that = e.target;
const newValue = `${that.value}${that.dataset.sizing || ''}`;
etc.
}
but I first tried to bind the function like that:
input.addEventListener('change', handleUpdate.bind(this));
But this inside the function still points to window and I don't understand why.
Is there no "right" way to bind the function to the element in this case?
What is this?
this is a special keyword in Javascript that refers to the executing environment of the function:
If you execute a function in the global scope, this will be bound to the window
If you pass the function to a callback for an event handler, this will be bound to the DOM element that raised the event
Binding
The bind method basically says, when you call the function, replace this with whatever my argument is. So, for example:
let a = {}
function test_this() {
return this === a;
}
test_this(); // false
test_this.bind(a)(); // true (.bind() returns the bound function so we need to call the bound function to see the result)
Additionally arrow functions are simply syntactic sugar for binding the function's this to the current value of this. For example,
let b = () => { /* stuff */ }
is the same as
let b = (function () { /* stuff */}).bind(this);
(basically, I know this is an oversimplication)
Your predicament
In the normal course of events (not using arrow functions), this is bound to the DOM element.
When you're executing the creation of the event handler input.addEventListener('change', handleUpdate.bind(this)); you're running in the global scope (so this === window). So you're effectively running input.addEventListener('change', handleUpdate.bind(window)); (which is the behavior you're noticing). And using the arrow function is the same thing.
If you want to replace the callback with an anonymous function you should instead do:
const handleUpdate = function (e) {
const that = e.target;
const newValue = `${that.value}${that.dataset.sizing || ''}`;
// etc.
}
I am trying to trigger a React setState when a feature is clicked. I try to edit the selectedFeature and show it's properties on the screen. But I get a "TypeError: Cannot read property 'setState' of undefined" Error message every time i try to execute the click method.
componentDidMount() {
...
function featureSelected(event) {
console.log(event.selected[0].getProperties());
this.setState({ selectedFeature: event.selected[0].getProperties() });
}
var changeInteraction = function() {
var select = new Select({});
select.on("select", event => featureSelected(event));
map.addInteraction(select);
};
...
}
This is the line that throws the error:
this.setState({ selectedFeature: event.selected[0].getProperties() });
This is my state property:
class MyMap extends Component {
state = {
selectedFeature: null
};
...
This is undefined
Use fat arrow function instead of the function keyword.
You add a new scope when you add a function. this becomes the this
of the function and not of the class anymore.
A fat arrow function passes the scope of this down and will allow you to call class methods like setState.
componentDidMount() {
...
const featureSelected = (event) => {
console.log(event.selected[0].getProperties());
this.setState({ selectedFeature: event.selected[0].getProperties() });
}
var changeInteraction = () => {
var select = new Select({});
select.on("select", event => featureSelected(event));
map.addInteraction(select);
};
...
}
The problem is a misconception of this
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Basically this refers to the closest function parent. In your case this refers to featureSelected.
Try creating a reference to the this that you need, by storing it into a variable.
componentDidMount() {
...
const myClass=this; //Reference to the above class
function featureSelected(event) {
console.log(event.selected[0].getProperties());
//Use that reference instead of this
myClass.setState({ selectedFeature: event.selected[0].getProperties() });
}
var changeInteraction = function() {
var select = new Select({});
select.on("select", event => featureSelected(event));
map.addInteraction(select);
};
...
}
I have problem and I don't know how to solve it:
this.bWords.push(word);
^
TypeError: Cannot read property 'push' of undefined
here is my code:
function multiWords(words) {
class AWords {
constructor(words = []) {
this.words = words;
this.addWordFn = () => {};
}
setAddWordFn(fn) {
this.addWordFn = fn;
}
passWords() {
this.words.forEach(word => this.addWordFn(word));
}
}
class BWords {
constructor() {
this.bWords = [];
}
addWord(word) {
this.bWords.push(word);
}
}
let x = new AWords(words);
let y = new BWords();
x.setAddWordFn(y.addWord);
x.passWords();
return y.bWords;
}
console.log(multiWords(["one", "two", "three"]));
Do you have any ideas why there is different this value?
Many thanks
Pati
It appears that the problem occurs here:
this.words.forEach(word => this.addWordFn(word));
because the function you've set for addWordFn here:
x.setAddWordFn(y.addWord);
Needs a different value of this than you are calling it with. You can fix it by binding the right value of this to your callback:
x.setAddWordFn(y.addWord.bind(y));
Remember that for regular functions, the value of this inside the function is determined by how the function is called. When you call a function with obj.method(), the this value inside of method() will be set to obj. So, you're calling addWord with the wrong this value because you've made it a method of some other object (that does not also have the data it needs) and are calling it off that object.
I've asked this in the past but still not understanding why my this is always window and not the calling object.
on the page there is button control:
<input type="button" value="Press Me" id="buttonPressMe" #click="pressMeClicked" />
This is the component and under methods is where I have functions:
pressMeClicked() is the function that gets called:
pressMeClicked: () => {
console.log(this.el)
var dd = this;
console.log('pressMeClicked');
}
The problem is this is not the component object in the pressMeClicked() function. It's always the window object. The code below shows how I add an event listener to the element. And either of the two options I used does call the pressMeClicked function. The only problem is that this is not the component obj but window:
const funcBind = function(obj, method, args = []){
return function(){
return method.apply(obj, args);
}
}
const funcProcess = (component, elements) => {
const fn = component.methods['pressMeClicked'];
const methodCall = funcBind(component, fn);
const elem = component.selector('#buttonPressMe');
elem.addEventListener('click', () => {
// Tried this
fn.bind(component)()
// Tried this also
methodCall();
}
}
When I step into the function methodCall(), obj is the component.
Any help would greatly be appreciated
pressMeClicked is an arrow function, which is a non-bound function. Because of that, this will always refer to the value of this inside the lexical scope of its containing function. To fix this change the arrow function definition to a regular function (method):
// Instead of:
pressMeClicked: () => {
// ...
}
// Do this:
pressMeClicked() {
// ...
}
// or:
pressMeClicked: function() {
// ...
}