This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
here is my code, Now some people may say why not just include the one line code in that function block but i don't want to, how do i achieve that. How can i call this.click method on "click" event of the button
var i = 0;
function el() {
this.type = "button",
this.el = false,
this.click = function () {
this.setHtml(i++);
},
this.setHtml = function (t) {
this.el.innerHTML = t;
}
fragment = document.createDocumentFragment(),
element = fragment.appendChild(document.createElement(this.type));
element.setAttribute("data-el", this.type);
element.innerHTML = "Default Button";
this.el = element;
attachEvent("click", this);
}
// this should be a seperate function ....
function attachEvent(ev, me){
//me doesn't work, but i want it to call the click method
me.el.addEventListener("click", me.click, false);//....
}
div = new el();
document.getElementById('areaA').appendChild(div.el);
Change this:
me.el.addEventListener("click", me.click, false);//....
to this:
me.el.addEventListener("click", me.click.bind(me), false);//....
When you pass only me.click, you are just passing a reference to the click function and the binding to me is lost. .bind() will create a self-binding stub function that will give you the right this value when the event handler is called.
Related
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.
}
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I'm working on a workaround for another problem I'm having but with this I got a "this.setState is not a function" error. I found this answer which advises to bind it within the constructor, which I did.
This is part of my constructor:
this.newProject = this.newProject.bind(this);
this.openProject = this.openProject.bind(this);
this.saveProject = this.saveProject.bind(this);
And this is my function:
// Open a file, set data as session item and reload page
openProject(FileObject) {
var read = new FileReader();
read.readAsBinaryString(FileObject);
read.onloadend = function() {
//sessionStorage.setItem("reloading", "true");
//sessionStorage.setItem("data", read.result);
//document.location.reload();
// Fix for missing data.
var jsonData = JSON.parse(read.result);
for (var i = 0; i < jsonData.blocks.length; i++) {
var name = jsonData.blocks[i].name;
var id = jsonData.blocks[i].id;
var ip = jsonData.blocks[i].ip;
var port = jsonData.blocks[i].port;
this.setState( { blockCount: (i + 1), });
// Add block to the list
this.setState({
blocks: this.state.blocks.concat({
id: id,
name: name,
ref: React.createRef(),
positionX: window.innerWidth*0.4 - 125 / 2,
positionY: 75 + ( 50 * this.state.blocks.length),
links:[],
requires: this.state.parameters.blockRequires
})
});
}
}
}
What would be a solution to this?
this belongs to the closest function context, which in your case is read.onloadend = function()...NOT the class.
You can solve this problem by assigning the class-level this to a new variable before you enter that ad-hoc function:
openProject(FileObject) {
var read = new FileReader();
read.readAsBinaryString(FileObject);
var that = this;
read.onloadend = function() {
// ...
that.setState(/*... etc*/
And of course you'll want to change all instances of this within your onloadend callback function to that (or whatever variable name you choose).
*Edit: as #MDTabishMahfuz describes, you can also use an arrow function, because unlike the function declaration, an arrow function:
Does not have its own bindings to this or super
Binding this is necessary for functions of the class but you have an additional callback (onloadend function) which is a different function and the component's this is not available there.
Conventional Functions in JS have their on this in their context. You can either use the method suggested by #David784 or use an arrow function for the onloadend handler like so:
read.onloadend = () => {
....
this.setState(....);
....
}
Arrow functions have this from the parent's context, that is the React component in your case.
This question already has answers here:
"this" keyword in event methods when using JavaScript prototype object
(4 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 2 years ago.
If a function inside an event listener is called, say for instance, window.load, are all other functions inside said function expected to be ran on load as well? I have an issue with a function being called on window load and that function calling another function. At the last step I want to add an event listener to watch for form submission. However the listener function has no access to the the variables called from the original load listener function.
var Handler = {
ajaxURL: null,
domIDs : null,
httpRequest : null,
init: function(config) {
this.httpRequest = {};
this.initConfig(config);
this.setLoadHandler();
},
initialize: function() {
this.initializeDocumentNodes();
},
setLoadHandler: function(){
var self = this;
this.addEvent(window,'load', function() {
self.initialize();
});
},
initializeDocumentNodes: function() {
this.dom = {};
for(var key in this.domIDs) {
this.dom[key] = document.getElementById(this.domIDs[key]);
}
this.dom['loginForm'].addEventListener("submit", function(ev) {
ev.preventDefault();
console.log(this.dom['userNameLoginInput']);
console.log(this.dom['passwordLoginInput']);
});
},
this.dom is undefined inside the form submit listener.
this.dom['loginForm'].addEventListener("submit", function(ev) {
ev.preventDefault();
console.log(this.dom['userNameLoginInput']);
console.log(this.dom['passwordLoginInput']);
});
Could someone please help me to understand this? Thank you so much.
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am building an app with Javascript and OpenLayers and while it's going fairly well, I am stuck at what I feel could be an easy problem for someone experienced.
Here is part the code where the problem lives :
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender = {};
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
let baseLayerElementValueRight = this.value;
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === baseLayerElementValueRight
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element;
console.log(layerRender);
}
});
},
false
);
}console.log(layerRender)
So Basically, I need to apply a method on the "layerRender" object variable outside of the event callback and I am quite new to programming and I struggle to find a solution to access the variable value
The console.log in the callback's event output the Object I want everytime I click on a given radio type input, but the console.log outisde it outputs an empty Object and of course don't update everytime I the event is happening.
How could I do to access the layerRender value outside of the callback?
Thanks a lot
your last console.log only happens once as the code runs through... you first declare the variable. Then you add an eventListener in a for loop then finally do console.log code executes. and it executes NOT when you're clicking
const baseLayerElementsRight = document.querySelectorAll(
'[name="baseLayerRadioButtonRight"]'
);
let layerRender;
for (let baseLayerElementRight of baseLayerElementsRight) {
baseLayerElementRight.addEventListener(
'change',
function() {
console.log('Click happened');
layerGroupRight.getLayers().forEach(function(element) {
let baseLayerNameRight = element.get('title');
element.setVisible(
baseLayerNameRight === this.value
);
let elementVisibility = element.get('visible');
if (elementVisibility) {
layerRender = element; // assign element to layerRender
// console.log if element is visible only
console.log(layerRender);
}
});
},
false
);
}
console.log(layerRender); // Happens when function initialise NOT when click happens
This question already has answers here:
How to removeEventListener that is addEventListener with anonymous function?
(5 answers)
Closed 6 years ago.
I an attaching event listeners in input box by using ID. so its working fine but I want to remove event listeners its will not work for me.
document.getElementById("myInput").addEventListener("keyup", function({
console.log(document.getElementById("myInput").value);
});
document.getElementById("myInput").removeEventListener("keyup",function() {
});
The second argument needs to be the event listener you want to remove (so you need to keep a reference to that function around instead of putting a function expression directly as the argument to addEventListener).
You're passing it a brand new function. It doesn't get removed, because that function wasn't listening in the first place.
var in = document.getElementById("myInput");
function myListener (event) {
console.log(in.value);
}
in.addEventListener("keyup", myListener);
in.removeEventListener("keyup", myListener);
Try that
var fn = function({
console.log(document.getElementById("myInput").value);
}
document.getElementById("myInput").addEventListener("keyup", fn);
document.getElementById("myInput").removeEventListener("keyup", fn);
var body =
document.querySelector('body'),
clickTarget =
document.getElementById('click-target'),
mouseOverTarget =
document.getElementById('mouse-over-target'),
toggle = false;
function makeBackgroundYellow() {
'use strict';
if (toggle) {
body.style.backgroundColor = 'white';
} else {
body.style.backgroundColor = 'yellow';
}
toggle = !toggle;
}
clickTarget.addEventListener('click',
makeBackgroundYellow,
false
);
mouseOverTarget.addEventListener('mouseover', function () {
'use strict';
clickTarget.removeEventListener('click',
makeBackgroundYellow,
false
);
});
target.removeEventListener(type, listener[, options]);
target.removeEventListener(type, listener[, useCapture]);
the second argument is the eventlistener you want to remove, see this