In my project I have JS module, that adds event listeners on click:
$('.next-step').on('click', function () {
// do something
});
In another module I should create new event listeners that should work AFTER previous listener. Lets say I do something like this:
$('.next-step').find('#someId').on('click', function () {
// do another things
});
The problem is that second listener always works before first. How can I change this sequence?
You can use setTimeout() function to make it be excuted later.
$('.next-step').on('click', function () {
setTimeout(
function(){alert("foo");
},100)
});
It will be executed 100 miliseconds later so you will be sure that other events already were executed.
Note: you can change 100 to 1, it will be enough.
Related
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).
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.
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)
Consider following:
$('#theElement').on('click',function(){
$(this).animate(...);
$(this).doThis(...);
$(this).doThat(...);
$('anotherElement').animate(...);
$('anotherElement').doThis(...);
$('anotherElement').doThat(...);
});
As you see, here is a simple delegate function for onClick event. Now how is possible to make during this function execution, no other event be triggered on "#theElement"?
I tried to use preventDefualt(), but it stops whole execution which means that animate(), doThis() etc will not run too.
Set a Boolean flag on the element when the function starts.
$('#theElement').on('click',function(){
$(this).data('flagname',true);
// ...
Test for the flag in your other events.
if (!$(this).data('flagname')) { // !(undefined) is true
// run code
}
Clear the flag when your animations are complete.
var $this = $(this); // 'this' is locally scoped
$this.animate(/* ... */, function() {
$this.data('flagname',false);
});
You have to nest them like this:
$(".yourclass").animate({}, time, function(){
$(".yoursecondclass").animate({}, time, function(){
});
});
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