I am using a simple script which :
displays a message after 3 seconds if user has not clicked by then (using a setTimeout),
then if user clicks within 5 seconds, then the message should not appear within the defined setTimeout,
after this previous click if the user does not click for 5 seconds, then the user will see the message and so on...
this goes on a like a loop.
My script acually works but I have an issue because it seems it is double firing "exponentially". I think my error is how I created this "loop" and self referencing the setTimerForMsg inside itself.
Here is a Demo: https://jsfiddle.net/3wm7z576/11/
Here is the code:
html
<div id="zone">
<span id="msg" class="displayNone">this is the messager</span>
</div>
js
setTimerForMsg(3000, 5000);
function setTimerForMsg(initial_timelaps, new_timelaps) {
var timer = setTimeout(showMsg, initial_timelaps);
$("#zone").on('click', function(e) {
//if user clicks before msg appears (but after timer was initiated )
clearTimeout(timer);
//if user went beyond timer laps and msg already visible on Step (n)
//remove it when move to Step (n+1)
$('#msg').addClass('displayNone');
console.log("message1");
//loop the process for the next Step
setTimerForMsg(new_timelaps, new_timelaps);
});
}
function showMsg() {
$('#msg').removeClass('displayNone');
console.log('message2');
}
This issue is important because while this script is simple, in my real app it does other things that could drain the browser performance so I can't have them be done 64 times!
And you can see here in the console of the Demo, each time I click the events occur twice : 2 times , then 4 times then 8, then 16, then 32 times, and so on...
use $("#zone").off('click', ... to remove the eventListner you previously added. Otherwise you're just adding more and more click actions.
Documentation here
Well first of all your new_timelaps parameter is unused, this might cause some confusion.
As for the exponential growth in logs, this is caused by the fact that you don't remove your event listener, so everytime the time for your interval is passed or you click ur button another click event with the same function is aplied to your button.
How you would solve this is by using
$( "#zone").unbind( "click" )
to make sure the event is only aplied once and not get aplied again or the old ones get removed.
Related
A website shows a cookie consent after arround 1-2 seconds, if a user has not give a consent. That means, the consent is not in the source directly but in the dom after 1-2 seconds.
I have to detect if a user clicks on a button inside of the consent div. If I use the document ready function, the click is not detected. I have to use setInterval because setTimeout doesn't work. The reason is that another window has to be opened in the Consent and therefore I cannot use a fixed time as with a timeout.
The Consent div is sourrended by a div with the class name "cmp-consent". I check the dom with setInterval every 1800ms for that div. If the div is not existend after 1800ms the user has already given the consent and I clear the setInterval.
BUT:
If the div exists, it waits until the user clicks on the second button in the consent header. When this click is made, another click is made and the window is closed. This is working very well.
The problem is, if a user does not click this button (consent-header button: eq (1)) immediately, the setInterval will of course continue to run. You can see the counter in front of the console.log is increasing. If a user then clicks the button, the subsequent clicks are carried out as often as there is a setInverval. This takes too long if a user waits, for example, longer then a minute. The question is, how do you manage that an action is only carried out once in a setInterval.
Here is my script:
var userConsent = window.setInterval(function() {
if ($(".cmp-consent")[0]){
console.log('consent exists');
$( ".consent-header button:eq(1)" ).click(function(){
console.log('User clicked the button');
$(".primary button").click();
$(".close-icon").click();
window.clearInterval(userConsent);
});
} else {
console.log('consent given, remove interval');
window.clearInterval(userConsent);
}
}, 1800);
Here is a working example of #cloned's suggustion.
document.addEventListener("click", function(e) {
for (var target=e.target; target && target!=this; target=target.parentNode) {
// loop parent nodes from the target to the delegation node
if (target.matches('.consent-header')) {
handler.call(target, e);
break;
}
}
}, false);
function handler() {
console.log('do stuff');
}
<div class="consent-header">
<button>I agree</button>
</div>
I wrote the code in javascript (jQuery), that allows a user with every click of a button to create a "box" on the web site and to get an alert message after this box was clicked.
It works like this:
1) When the user presses the button "Add (#addBox)" - jQuery appends a new line to the HTML file, that creates the "box" (it looks like a box because of the CSS code).
2) If the user presses the box, it sends out the alert message "Hello".
But if I add multiple boxes and then click on the first one, instead of sending out one alert message, it sends it out as many time as the number of boxes been created.
Example:
1) I have 1 box. By pressing on it, I receive 1 alert message.
2) I have 2 boxes. By pressing on the top one, I receive 2 alert messages.
By pressing on the second one, I receive 1 message.
3) I have 3 boxes. By pressing on the top one, I receive 3 alert messages.
By pressing on the second one, I receive 2 messages.
By pressing on the third one, I receive 1 message.
The function of sending an alert message is looping for some reason.
And so here is the code:
function addBox()
{
$("#addBox").on("click", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
}
boxCount();
});
}
function boxCount()
{
$(".desiredBox").on("click", function () {
alert("Hello");
});
}
Any ideas, how to make them send only one message each, preventing the function "boxCount()" from looping?
Every time the function boxCount is invoked an event handler is added to existing elements i.e. ".desiredBox". thus you are getting multiple alerts.
As you are creating elements dynamically.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
General Syntax
$(document).on(event, selector, eventHandler);
Ideally you should replace document with closest static container.
Complete code
$("#addBox").on("click", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
});
$(document).on('click', '.desiredBox', function(){
//Your code
});
Use event delegation so you don't keep adding the click event to .desiredBox over and over again:
$(document).on("click", "#addBox", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
$(".desiredBox").trigger("click");
});
$(document).on("click", ".desiredBox", function () {
alert("Hello");
});
I've got slider in template glitching, and code is minimized. So, got tired of looking for the cause of the problem and decided to use a quick hack.
I need to fire a div click multiple times.
I've used this piece of code to trigger a click
$('.control-prev').trigger('click');
Works fine for one time click.
Now, how do i make it click multiple times?
http://jsfiddle.net/br4Lmyso/ (warning: creates three alerts, just to quickly show it works)
// set your count to whatever you want. Get a reference to the div
// so you're not querying the DOM everytime.
var triggerCount = 3;
var triggerDiv = $('.control-prev');
// loop!
for(var i = 0; i < triggerCount; i++) {
triggerDiv.trigger('click');
}
To be clear, trigger(...) does not simulate the click behavior and there is no way you can simulate the click behavior. What it does is to call the function that handle given event. These two are total different. For example:
$('#test').click(function() {
console.log("Clicked");
});
$('#test').dblclick(function() {
console.log("Double Click");
});
$('#test').trigger('click');
$('#test').trigger('click');
Despite of rapidly trigger two clicks, the double click will not trigger.
I'm working on my first program using jQuery, but I'm having an issue. I have a dialog pop up on pageLoad that asks the user to select a date and a turn. Right now, for debugging purposes, I have it alert every time .click() executes, and for some reason, it seems like it executes before the user clicks and immediately afterward.
There are three radio buttons, Turns 1, 2, and 3. When the user clicks Turn 1, the alert should say "1". When the user clicks Turn 2, the alert should say "2", etc. But for some reason, it alerts the previous value as well as the new one. I searched all of my code, and there is only one alert, so I can't figure out what is calling click() twice. I've tested it in IE and Chrome and it happened both times.
This is my .click() function:
$("#turn-radio")
.click(function () {
turnvalue = $("input[name='turn-radio']:checked").val();
alert(turnvalue);
});
If you check this jsfiddle, you'll see the rest of my code, which will hopefully make it easier to figure out what my problem is.
Thanks!
You need to change selector: as your radio button IDs are different and you were giving name as a selector that's why you were facing that problem:
$("input[name='turn-radio']")
.click(function () {
turnvalue = $("input[name='turn-radio']:checked").val();
alert(turnvalue);
});
Updated Fiddle
changing
$("#turn-radio") to $("#turn-radio label")
causes only one popup displaying the previous value
But, personally i would
$("#turn-radio input").change( function() { /* do stuff */ } )
Suppose you want to display an alert 3 seconds after there no changes in the DOM just after pressing a button that triggers a lot of changes.
An example with a button gotten via jQuery:
$someButton.on('click',function(){
setInterval(function(){
if( noChangesSinceLastTime()){
time += 100;
}
else{
time = 0;
}
if( time == 3000){
alert("3 seconds without changes!");
}
},100);
});
Assume that the click event on that button has some other binding that excecutes a series of functions for DOM manipulation.
How could I achieve something as the noChangesSinceLastTime()function?
More on my specific problem
I have an HTML+JS+CSS slideshow which works with many simultaneous clients in a network.
When a new client joins, he is automatically sent to the start of the current slide being watched by others.
What I want to do is that, just after it finishes loading the current slide, trigger the clicks necessary to sync the new client with others (since every click inside a slide triggers an animation step, and most slides have multiple steps).
I cannot add a callback in the JS slideware, since it's an obfuscated JS not made by me.
This is just pseudo code, but you could try something like this:
timer = setTimeout(function(){
alert("3 seconds without changes!");
}, 3000);
if(/*some change happens*/) {
clearTimeout(timer);
}
You could listen to all of the DOM Mutatation events and set a flag if any of those are were triggered.
Then in you interval function, you could check that flag and do whatever logic you want. =).
Regards,