I'm not being able to make a function of an Event Listener self invoke and the listener to work.
The following code executes the function, but the Event Listener don't work:
window.addEventListener("resize", (function () {
document.getElementById("divMenu").innerHTML = document.getElementById("divTop").offsetWidth
})())
The function will set a needed (dynamic since the beginning) CSS style essential to the website formatting. The "resize" function MUST be executed at load.
Is it possible to make this, or should i create a separate Self Invoking Function and call it on the Event Listener?
When you immediately invoke the function, it's return value is put in it's place (window.addEventListener('resize', undefined)). Instead, define your function outside of the event listener then add it and call it.
function onResize() {
document.getElementById('divMenu').innerHTML = document.getElementById("divTop").offsetWidth;
}
window.addEventListener('resize', onResize);
onResize();
Technically, you could make this work using a self-invoking function but it's a bit screwy and I wouldn't suggest it.
window.addEventListener('resize', (function onResize() {
document.getElementById('divMenu').innerHTML = document.getElementById("divTop").offsetWidth;
// Works because it returns a function
return onResize;
})());
Your IIF returns undefined, but eventlistener must be a function, or link to function. Add return to your IIF or pass function:
Anonymous function:
window.addEventListener("resize", function () {
document.getElementById("divMenu").innerHTML = document.getElementById("divTop").offsetWidth
}))
IIF, that returns a function
window.addEventListener("resize", (function () {
return function(){
document.getElementById("divMenu").innerHTML = document.getElementById("divTop").offsetWidth
}
})())
Edited (invoke assignment on startup):
window.addEventListener("resize", (function () {
function set_innerHtml(){
document.getElementById("divMenu").innerHTML = document.getElementById("divTop").offsetWidth
}
set_innerHtml();
return set_innerHtml;
})())
Related
I am creating a function that handles a bunch of stuff around pagenating and sorting a table. It contains a key function that submits the db query and updates the display table.
I want to be able to access that inner function/method from both inside the function and also from outside on the object created.
testFunction = function() {
keyMethod = function() {
console.log('ya got me');
};
document.getElementById('test').addEventListener('click', function (e) {
keyMethod();
});
keyMethod();
};
myTest = new testFunction();
myTest.keyMethod();
testFunction = function() {
this.keyMethod = function() {
console.log('ya got me');
};
document.getElementById('test').addEventListener('click', function (e) {
// would have to use bind here which then messes up trying to
// find the correct target etc.
keyMethod();
});
this.keyMethod();
};
myTest= new DrawShape();
myTest.keyMethod();
Creating it the first way means that the keyMethod function is available everywhere within the testFunction but I cant call it from outside.
Creating it the second way means I can do myTest.keyMethod but I then cant call it from within an inner function without using bind everywhere.
Is there a better way..?
You could replace the function provided as callback with an arrow function or use bind the function first like you already said.
testFunction = function() {
this.keyMethod = function() {
console.log('ya got me');
};
// Replace callback by simply providing the function to call.
// This works as long as you don't use the `this` keyword inside the
// provided function.
document.getElementById('test').addEventListener('click', this.keyMethod);
// If your callback method does use the `this` keyword you can either use an
// arrow function or bind the function up front.
document.getElementById('test').addEventListener('click', event => this.keyMethod());
document.getElementById('test').addEventListener('click', this.keyMethod.bind(this));
this.keyMethod();
};
console.log("constructor output:");
myTest = new testFunction();
console.log(".keyMethod() output:");
myTest.keyMethod();
console.log("click event output:");
<button id="test">test</button>
I write code in pure JS and I need to have reusable callback for my event listener within the class. It is required to meet following:
reusable by another functions
event listener needs to be revocable by another functions
I need to pass argument (event)
I need to be possible to call another function from the callback (this.doSomething())
I tried define callback as method and also as function expression but every time I solve one issue another occurred. I have walked through many questions here too but still can not make my code to work.
class Foo {
constructor() {
functionA()
this.howAndWhereToDefineThisCallback = function(event) {
event.preventDefault();
this.doSomething();
}
}
functionA() {
let el = document.getElementById('element1');
el.addEventListener( 'click', howAndWhereDefineThisCallback );
this.functionB();
}
functionB() {
let el = document.getElementById('element1');
el.removeEventListener( 'click', howAndWhereToDefineThisCallback );
}
doSomething() {
// something meaningful
}
}
How can I modify my code to use it the way I just described?
Here you have an implementation:
// Callback defined outside the class.
function callback(event) {
this.doSomething();
}
class Foo {
constructor(cb) {
// Important: You have to bind it.
this.cb = cb.bind(this);
this.functionA();
}
functionA() {
let el = document.getElementById('element1');
el.addEventListener('click', this.cb);
}
functionB() {
let el = document.getElementById('element1');
el.removeEventListener('click', this.cb);
}
doSomething() {
console.log('doing something...');
}
}
const foo = new Foo(callback);
// foo.functionB();
<button id="element1">
Click here
</button>
If you want to reuse your callback function, simply put it outside of your class scope. In order to call another function from your callback, just put that function as a argument of your callback, for example:
var howAndWhereToDefineThisCallback = function(event, anotherCallback) {
event.preventDefault();
if (anotherCallback) anotherCallback();
}
To use the callback in your class method:
el.removeEventListener( 'click', function(event) {
howAndWhereToDefineThisCallback(event, this.doSomething);
});
I try to make a timeline that is dynamicaly loaded when scrolling.
Due to this I need the scroll event, combined with React.
window.addEventListener("scroll", console.log('scroll'), true);
This should console log a scroll every time I scroll, but it just log it once, then nothing
EDIT:
If I use it in my real application now, with this code :
callbackFunc = () => {
for (var i = 0; i < items.length; i++) {
if (this.isElementInViewport(items[i])) {
items[i].classList.add("in-view");
}
}
}
componentDidMount() {
window.addEventListener("load", function (event) { this.callbackFunc(); }, true);
window.addEventListener("resize", function (event) { this.callbackFunc(); }, true);
window.addEventListener("scroll", function (event) { this.callbackFunc(); }, true)
}
It says callbackFunc is not a function
This isn't working because the event listener expects a function as it's second argument (or an object implementing the EventListner interface) which it will call when the "scroll" occurs. console.log is a function, but console.log("scroll") isn't a function, its a called function. And so the value you are technically putting as the second argument is undefined (as console.log("scroll") returns undefined).
const a = console.log("scroll");
console.log(a); // undefined (the value of your second arugment)
So, you need to wrap the console.log() in a function, so the function is called, which will then call your console.log() method. You can achieve this by using an ES6 arrow function:
window.addEventListener("scroll", _ => console.log('scroll'), true);
window.addEventListener("scroll", _ => console.log('scroll'), true);
body {
height: 200vh;
}
As per your edit, the arrow function should solve your issue. Currently, the window is calling your event listener function, so this is referring to the window, not the context of your app. Using an arrow function should fix this (as an arrow function doesn't have it's own this).
Try this:
window.addEventListener("scroll", function(event) { console.log('scroll'); }, true);
Try adding it in reactjs
componentDidMount() lifecycle function
I'm using the implementation of debounce from https://davidwalsh.name/javascript-debounce-function.
The question now is: How do I get the event (e.target) from the eventlistener and use it inside the debounced function?
This is what I've come up with:
document.querySelector('textarea')
.addEventListener('input', (e) => {
debounce(
() => { console.log('debounce at '+e.target.value); },
1000,
false
)(e); // add (e) so that the function debounce returns gets called inside the anonymous function
});
The problem is that it triggers immediately (and the debounce effect gets effectively killed).
you need to wrap the input event handler, like so:
function handler(e) {
console.log('debounce at '+e.target.value);
}
const debouncedHandler = debounce(handler, 1000)
document.querySelector('textarea').addEventListener('input',debouncedHandler, false)
now when the event fires it will call the same handler and not a new one
demo
While implementing a closure function, I have noticed that if I provide a "named function" as an event handler then it gets executed straightaway when the event gets attached to the buttons. However, if I keep the function inline as an anonymous function then it doesn't execute straightaway and fires only on the
event happens. Please can anyone explain this behaviour?
var buttons = document.getElementsByTagName('button');
//function buttonHandler(buttonName){
//// return function(){
//// console.log(buttonName);
//// }
// alert("hello");
//}
var buttonHandler = function(name){
alert(name);
}
for(var i = 0; i < buttons.length; i += 1) {
var button = buttons[i];
var buttonName = button.innerHTML;
button.addEventListener('click', buttonHandler(buttonName));
button.addEventListener('click', function(buttonName){
alert("hi");
});
}
Many Thanks!
This has nothing to do with the function being named. This is about your code explicitly calling the function.
If you put (some,arguments) after a function then you will call it.
!foo() // calls the function
!function () { }(); // Also calls the function
So:
button.addEventListener('click', buttonHandler(buttonName));
Calls buttonHandler, passing buttonName as an argument to it
Calls addEventListener, passing "click" and the return value of 1 to it
buttonHandler has no return statement, so that return value of undefined which isn't a useful thing to pass to addEventListener.
The commented out version of buttonHandler returns a function. That would be a useful thing to pass to addEventListener.
As pointed out in the answers above the code
button.addEventListener('click', buttonHandler(buttonName));
is making direct call the function so if you only need to pass parameters to the handler function you may use an anonymous function instead of directly calling the function as recommended here (https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener)
I updated my code as below
button.addEventListener('click', function (){ buttonHandler(buttonName)}, false);