I have an add-to-bag button used throughout our site and we want a dynamic popup to appear to acknowledge what was just added, and then it goes away. I'm finding that if you click another add button, it has the previous dialog's timeout attached. To fix this so the next dialog has its own 10,000 setTimeout rather than whatever is left over from the last one I have come up with the following code (that doesn't do the trick).
$(document).ready(function ()
{
// Create object for future dialog box - so it's available to the close method
var addToBagDialogVar = $('<div id="addToBagDialogBox"></div>');
var autoCloseTimeout = 10000;
var dialogTimer;
$(".addToBagPU").click(function (e)
{
var result = "";
$.get(this.href, function (data) { SetData(addToBagDialogVar, data); });
return false;
});
// Start listening for the close link click
$(document).on("click", "#bagPUCloseLink", function (event)
{
event.preventDefault();
CloseDialog(addToBagDialogVar);
});
function SetData(addToBagDialogVar, data)
{
result = data;
var regex = data.match("{{(.*)}}");
var bagCount = regex[1];
addToBagDialogVar.html(result).dialog({
open: function ()
{
clearTimeout(dialogTimer);
$(".ui-dialog-titlebar-close").hide();
SetBagCount(bagCount),
dialogTimer = setTimeout(function () { CloseDialog(addToBagDialogVar); }, autoCloseTimeout);
},
show: { effect: "fadeIn", duration: 800 },
close: function () { clearTimeout(dialogTimer); },
width: 320
});
}
function CloseDialog(closeThisDialog)
{
closeThisDialog.dialog("close");
closeThisDialog.dialog("destroy").remove();
}
});
The dialog is loaded with dynamic content from an external .Net page with product data and has a close link inside that page, which is why the dialog is loaded into addToBagDialogVar so it's available to CloseDialog.
All of that works just fine. It's just the reset of the timer that doesn't appear to be happening. If I go down a page of products and add each one to my bag, the 3rd or 4th dialog is only up for a second or so because they have all been using the first dialogs setTimeout.
I've read and read and tried too many different ways to remember and now my brain is mush.
I propose an alternate explanation for the behavior you're observing. When you click the first "add to cart", a timer is started. As you go down the page clicking "add to cart", a new timer is started each time. There's no overlap, just a bunch of separate timers running normally (although incidentally, each new dialog box blows away the timer ID you've previously created; I'll come back to this).
When your first dialog's timer expires, the dialog closes itself via the HTML ID, meaning it closes itself with something like a jquery $('div#addToBagDialogBox').closeOrSomethingLikeThat(), that is, every dialog inside a div with an id of addToBagDialogBox. The first timer expiration is closing all of your dialogs, because they all use that same HTML ID. The other timers are running perfectly, but when they expire there's nothing left for them to do.
You can fix the early-close problem by assigning a unique HTML ID to each dialog you create. And you'll want to manage your timer IDs on a per-dialog basis as well, such that each dialog has its own timer ID.
Edit: Just for nerdy grins, think about the details of the scenario you described. Your first timer is running, counting down normally, and you start four other timers while the first dialog is still there. The ID of the fifth timer is in your variable dialogTimer. So when the first dialog's timer expires, the close processing occurs, and you call clearTimeout with the ID of the fifth dialog's timer. So your first dialog's timer expired, the dialog closed all the other dialogs, and the cleanup cancelled the fifth timer. There are three other timers still running, their IDs lost forever. They finally expire and their shutdown functions run, but they're totally without effect, their companion dialogs long gone. Sorry, bona fide nerd here.
Related
Have a slider in website header that uses JavaScript and Jquery to change its tabs every 6 seconds or when the user clicks one of its tabs. I use it in my project in Webflow (a page builder) and the problem I face is that whenever slide changes, currently focused form window loses focus.
I'm no programmer even though I'm learning js now, but if after some investigation I think that the .w--current class is used both for slider and form focus in Webflow's master js file.
Here is my live project:
https://bauserwis-com-pl.webflow.io/
I found some solutions that use IntersectionObserver API to tell if the header is in viewport and stop the setInterval timer, but I struggle with integrating it with my code. Or perhaps is there a different solution? I don't mind slides changing in the background, I only want to stop the form from losing focus.
Thanks in advance.
var tabTimeout;
clearTimeout(tabTimeout);
tabLoop();
// Cycle through all tabs.
function tabLoop() {
tabTimeout = setTimeout(function() {
var $next = $('.tabs-menu').children('.w--current:first').next();
if($next.length) {
$next.click(); // user click resets timeout
} else {
$('.standard-tab:first').click();
}
}, 6000); // 6 second tab loop (change this)
}
// Reset loop if a tab is clicked
$('.standard-tab').click(function() {
clearTimeout(tabTimeout);
tabLoop();
});
});
I am building a survey in Qualtrics and use the method clickNextButton to automatically direct the participant to the next page with questions. I implemented the method in several following pages. Furthermore, participants are also able to click the next button themselves. The problem arises when they do so: if they click on the next button before the time limit, in the next page the method directs the participant earlier than given to the page after that one.
this.hideNextButton();
var that = this;
(function(){that.clickNextButton();}).delay(40);
For example, I set the time limit on 40 seconds on every page. On page 1, the participant manually clicks on the 'next button' after 10 seconds. What happens then is that on page 2, the participant is forwarded to page 3 after 28 seconds instead of 40. If he would have clicked on the 'next button' on page 1 after 5 seconds, he would have been forwarded on page 2 to page 3 after around 33 seconds. So it apparently depends on his click speed on page 1 when he will be directed on page 2. How can I prevent this?
Rather than using the timer for automatic redirection. call respective on click method when the question is answered so it will redirect to the respective page. and also reset the timer on every page redirection.
You need to clear the timeout if the respondent clicks the Next button themselves (delay is just a prototypejs implementation of setTimeout). Do it something like this:
Qualtrics.SurveyEngine.addOnReady(function() {
this.hideNextButton();
var that = this;
var timer = setTimeout(function() { that.clickNextButton(); },4000);
Qualtrics.SurveyEngine.addOnPageSubmit(function() { clearTimeout(timer); });
});
I found this article helpful for what I was needing to do, which was have a slideshow of sorts with a tab and tab_container using JavaScript. The code works great:
Automatic tab switch in javascript or jquery
However, what I want it to do is if you let the page run, it keeps rotating between the tabs. But if a tab is manually clicked on (example, they want to read the content on that tab) it stops the auto-rotation of the tabs for the duration of while they are on that webpage. If the page is refreshed, or they go back to the page, it starts the tab rotation again.
I'm not sure the Javascript code that I can add to the above example to make the auto-rotation stop.
Thanks in advance for the help!
You can use clearInterval to stop the setInterval function from running. setInterval returns an ID and you can pass that ID to clearInterval to stop it, e.g.
var intervalID = setInterval(function() {
....
clearInterval(intervalID);
So just make the code
var intervalID = setInterval(function() {
....
tabs.on('click', 'a', function(e) {
clearInterval(intervalID);
$(this).trigger('slides.swap');
e.preventDefault();
});
I'd also change the setInterval function from triggering a click to just straight-up triggering slides.swap, so that you know the difference between a triggered click and a user's click:
$('a:eq('+idx+')').trigger('slides.swap');
Here's the updated Fiddle from that question.
Firstly, I am quite new to programming, so please be gentle. Stack Overflow has been a wonderful resource for me, so thankyou to all of you contributors.
This one I cannot crack though, and it's a difficult search item, as you can probably tell by the cryptic title...
Anyway, I have a jQuery popup function which gets called from a events.register control. Essentially whenever a user clicks in the map it sends a request to a web service, gets the data back, populates a form which the user can then interact with and save data back to SQL.
It works really well I am happy with its progress.
One of the functions is to change the value in a table, I want the user to get a prompt to ensure they don't accidentally save something they don't intend. It works perfectly the first time after a refresh, but then each time after that it adds one confirm, then again, until eventually after the fifth time there are 5 confirms that appear one after the other. Once the user clicks through them the code runs fine and I get expected results.
I only call the confirm once (I think?) but, yeah, I am lost, here is my function, sorry if it is hard to read or poorly formatted:
function popup() {
j = jQuery.noConflict();
j(document).ready(function() {
//open popup
j("#detailsform").height(250);
j("#detailsform").fadeIn(1000);
positionPopup();
document.getElementById("condition").value = getCondition;
j("#selCatHead").hide();
j("#cats").hide();
//dispose tree
j("#dispose").click(function() {
if (confirm("Are you sure?")) {
disposetree();
}
else { return false; };
});
//save defect
j("#savedef").click(function() {
saveDef();
});
//fade in defects
j("#adddefect").click(function() {
j("#detailsform").height(400);
j("#selCatHead").fadeIn(1000);
j("#cats").fadeIn(1000);
});
//fade out popup
j("#close").click(function() {
j("#detailsform").fadeOut(500);
});
}); // close document ready function
//position the popup at the center of the page
function positionPopup() {
if (!j("#detailsform").is(':visible')) {
return;
}
j("#detailsform").css({
left: (j(window).width() - j('#detailsform').width()) / 2,
top: (j(window).width() - j('#detailsform').width()) / 7,
position: 'absolute'
});
} // close positionPopup function
//maintain the popup at center of the page when browser resized
j(window).bind('resize', positionPopup);
}; // close popup function
EDIT: Thanks to #jfriend00, removed function from popup call and turned off handler each time, eg:
function popup() {
j = jQuery.noConflict();
j(document).ready(function() {
//open popup
j("#detailsform").height(250);
j("#detailsform").fadeIn(1000);
//dispose
j("#dispose").off();
j("#dispose").click(function() {
disposeClickHandle();
});
//save
j("#savedef").off();
j("#savedef").click(function() {
saveDef();
});
});
and then:
function disposeClickHandle() {
if (confirm("Are you sure?")) {
disposetree();
}
else { return false; };
};
You should only install a click handler ONCE. If you install it multiple times, it will trigger multiple times.
So, everytime you call your popup() function it installs yet another click handler. And, then when you click, the click handler will trigger multiple times. You should either move your click handler installation outside the function that you call multiple times and put it in an initialization function that is only called once at the beginning OR you can remove the click handlers after your operation so when you install it again, it will only be installed one time.
Looking at other questions here they seem to report setInterval is disabled or slowed down when a tab is hidden. I am seeing a different problem - calls to setInterval appear to "stack" and then all get applied when the tab is shown.
In my case I have a slider which animates an image on the site homepage every few seconds. If I go to another tab for a minute or two then return, the slider goes crazy... all the animations fire one after another until it is caught up.
I tried adding code to stop the animation happening if another is already in progress, but it doesn't work... maybe the timer events get queued in some way that circumvents my test.
setInterval(function(){
if (!rotationQueued) {
rotationQueued = true;
rotate_slide('next');
}
}
So, I want the JS to pause when the tab is hidden - or to act as normal - anything but this!!
You could try something like this:
function runRotate() {
return window.setInterval(function(){
if (!rotationQueued) {
rotationQueued = true;
rotate_slide('next');
}
});
}
var run = runRotate();
window.addEventListener('focus', function() {
run = runRotate();
},false);
window.addEventListener('blur', function() {
window.clearInterval(run);
},false);
You would basically look to see if the browser window is focused or not and then run or disable the setInterval function depending on the event returned.