Suppose I have this event handler:
var mousewheel = function (e) { /* blah */ };
But, I want to debounce it. So I do this, which works as expected:
var mousewheelDebounced = _.debounce(mousewheel, 500);
$(document).on("mousewheel", function (e) {
e.preventDefault();
mousewheelDebounced(e);
}
But this doesn't work as expected:
$(document).on("mousewheel", function (e) {
e.preventDefault();
_.debounce(mousewheel, 500)(e);
}
I prefer the compactness of the second form. But no debouncing occurs.
I assume no reference to the mousewheelDebounced remains, so the underlying handler is called every time. Is that the reason? How can I clean up this code, if possible?
You can see a fiddle here.
On each mousewheel event (which occurs very often) you create a new version of debounce function. This function has no history, and doesn't know that on previous event there was another one created. So it just runs. That's why you should go with the first version.
Related
In javascript we have addEventlister, this listens to an even and calls a function called a listener function. Is an alternate approach possible where we increment the value of a "let variable" without using a function to do this in case of event being triggered?
Instead of this
let clickVar = 0;
x.addEventListener("click", RespondClick);
function RespondClick() {
clickVar++;
}
Sample Alternate implementation
x.addEventListner(click);
if (event == true){ clickVar++; }
======Edit======
Responding to the comment
The more I read this, the more it seems like an XY problem - is there something else you are trying to solve?`
In my view, the second approach is more intuitive. i.e. why create a function unless it's absolutely necessary.
Responding to the comment
There is no logic to how the second approach. The code you write will be executed once. If you want to run code more than once, you have to call a function. In order to run a function when an event happens, you need an event listener.
This simple amendment should take care of the one-time calling problem.
x.addEventListner(click);
if (event == true){ clickVar++; event=false; }
But the point I am trying to make is function could have been avoided, the code could be easy enough to speak, not only write.
Your second sample doesn't work. That simply isn't how event listeners work. You must use a callback function. If you think the first sample is too verbose, you can use an anonymous function:
let clickVar = 0;
x.addEventListener("click", function() {
clickVar++;
});
Or an arrow function in more modern versions of Javascript
x.addEventListener("click", () => {
clickVar++;
});
I want a function that will stop another function from running. It can be in JavaScript or jQuery.
It is for a game so div 1 is clicked over and over.
var makeBox=//a function;
$("#div1").click(function () {
makeBox
});
$("#div2").click(function () {
//stop make box
});
I hope it's more clear now
Why don't you try reassigning the event handler function?
var makeBox=//a function;
$("#div1").click(function () {
makeBox
});
$("#div2").click(function () {
$("#div1").click(function(){
//Do nothing
});
});
You might need to reassign it again later if you want it to work again but I don''t know exactly what you are trying to do.
No. JavaScript is single threaded. The click event won't be processed while another function is running.
(Your function might call other functions, using events, timeouts, etc which would allow for interruption, but there isn't any indication of that in your question).
All of this is happening for IE8.
Due to script import orders, I'm having a bit of code being executed before JQuery is loaded where I need to fire a custom event.
This event will be picked up later in another bit of code when I'm sure JQuery will have been loaded. So I'd like to use JQuery to pick up this event.
I saw this previously asked question: How to trigger a custom javascript event in IE8? and applied the answer, which worked, but when I'm trying to pick up the Event via JQuery, then nothing happens.
Here's what I've tried:
function Event() {}
Event.listen = function(eventName, callback) {
if (document.addEventListener) {
document.addEventListener(eventName, callback, false);
} else {
document.documentElement.attachEvent('onpropertychange', function(e) {
if (e.propertyName == eventName) {
callback();
}
});
}
};
Event.trigger = function(eventName) {
if (document.createEvent) {
var event = document.createEvent('Event');
event.initEvent(eventName, true, true);
document.dispatchEvent(event);
} else {
document.documentElement[eventName] ++;
}
};
Event.listen('myevent', function() {
document.getElementById('mydiv-jquery').innerText = "myevent jquery";
});
$(document).on('myevent', function() {
document.getElementById('mydiv-vanilla').innerText = "myevent vanilla";
});
Event.trigger('myevent');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="mydiv-jquery">Nothing</div>
<div id="mydiv-vanilla">Nothing</div>
PS: The snippet doesn't seem to work properly in IE. Here's a jsfiddle that should be working.
There are a few problems with this code.
You shadow the built-in window.Event without checking if it exists; this could cause problems for other scripts.
You don't preserve the this binding when calling the callback from your onpropertychange listener. You should apply the callback to the document rather than calling it directly so the behavior will be as close as possible to addEventListener.
You attempt to increment document.documentElement[eventName] while it is undefined. The first call will change the value to NaN, so onpropertychange should pick it up, but on subsequent calls it will remain NaN.
You make no attempt to have .on() recognize your Event.listen function, so naturally the code in Event.listen will never be executed from a listener attached with .on().
Have you tried using Andrea Giammarchi's CustomEvent shim?
I'm using Ben Alman's Throttle-debounce plugin.
When I call .throttle like that:
$(window).scroll($.throttle(250, function() {console.log(1)}));
throttled function fires.
But I have to check if scroll event isn't triggered. So when I do this
$(window).scroll( function(event) {
if (!event.isTrigger) {
$.throttle(250, function() {console.log(1)});
console.log(2);
}
});
I get only "2" in result. For some reason throttled function isn't fire. (the second console printing is to show, that code goes through throttled function)
I have never used Ben's plugin, but it looks like the throttle plugin doesn't fire the function it returns a new function that can only be fired x times per second (or whatever). This works because in JS functions are first-class Objects, so a function can just return a new function.
so if you want the function to fire you need to call it,
var throttledFunc = $.throttle(250, function() {console.log(1)});
$(window).scroll( function(event) {
if (!event.isTrigger) {
throttledFunc(event);
console.log(2);
}
});
you can also re-factor your first example like
var throttledFunc = $.throttle(250, function() {console.log(1)});
$(window).scroll(throttlesFunc);
internally jquery takes your passed in function reference and when the scroll event fires it does throttlesFunc(event)
There are 24 div-objects waiting/listening for a mouse-click. After click on one div-object, I want to remove the EventListener from all 24 div-objects.
for (var i=1;i<=24;i++){
document.getElementById('div'+i).addEventListener('click',function(event){
for (var z=1;z<=24;z++){
document.getElementById('div'+z).removeEventListener()//Problem lies here
}
//Some other code to be run after mouseclick
},false);
}
The problem is that the removeEventListener is nested in addEventListener and I need to define type, listener, caption as attributes to the removeEventListener method. And I think it is impossible to define the listener because of nesting.
I also tried to define a function name, but it didn't worked:
for (var i=1;i<=24;i++){
document.getElementById('div'+i).addEventListener('click',function helpme(event){
for (var z=1;z<=24;z++){
document.getElementById('div'+z).removeEventListener('click',helpme,false);
}
//Some other code to be run after mouseclick
},false);
}
You can tell the event listener to simply fire just once:
document.addEventListener("click", (e) => {
// function which to run on event
}, { once: true });
The documentation says:
once:
A boolean value indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
It should work with a named function. If your second approach does not work properly, try storing the initial listener into a variable, like this:
var handler = function(event) {
for(...) {
removeEventListener('click', handler, false);
}
};
addEventListener('click', handler, false);
Ps. if you care about speed, you may wish to consider using just one event handler. You can put the handler into the parent element of the divs, and then delegate the event from there. With 24 handlers your current approach probably doesn't have a very big performance hit, but this is something you should keep in mind if it ever feels slow.
For those who needs to remove after a certain condition (or even inside a loop too), one alternative is using AbortController and AbortSignal:
const abortController = new AbortController();
let handler = function(event) {
if(...) {
abortController.abort();
}
};
addEventListener('click', handler, {signal: abortController.signal});
The same answer:
element.addEventListener("click", (e) => {
// function which to run on event
}, { once: true });
You can read more here: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener