Openlayers setState on Select event - javascript

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);
};
...
}

Related

Javascript: node.onclick call a function not working

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);
}

trigger watch function in Vue 3 composition Api

I have set this reactive value inside the setup
const refValue = ref('foo');
and set a watch function to it
watch(refValue, function() {
console.log("activaded")
});
the watch function gets not activated if I manually change the value,
it gets only activated if a add a function which changes the value
const changeValue = function changedValue() {
console.log("fired");
return refValue.value = 12;
}
why does watch only gets triggered when using a function to change the value,
I thought that const refValue = ref('foo'); is reactive so watch should detect all changes
import { ref,watch } from 'vue';
export default {
setup() {
const refValue = ref('foo');
watch(refValue, function() {
console.log("activaded")
});
const changeValue = function changedValue() {
console.log("fired");
return refValue.value = 12;
}
return {
refProp: refValue,
changeFuncton: changeValue
};
},
};
Try out immediate option and use a function as first parameter that returns the observed property :
watch(()=>refValue, function() {
console.log("activaded")
},{immediate:true});
refValue type is an object.
vue watchs for refValue object reference change, not property change

Two classes one with reference to function to another different this value

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.

Call multiple function with parameters

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
}

Javascript object this is alway window

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() {
// ...
}

Categories

Resources