I'm developing a javascript based application and have continued to run into an issue that seems like a producer/consumer problem (it happens in both IE and firefox).
:Program Description:
There are two divs (A and B) in the page. A function is scheduled with timeouts to flip between the two divs every N seconds.
divs B has a form in it with buttons. the buttons have an on click call back set to them - the call back resets (refreshes) the form.
:Implementation Bug/Problem:
When div B displays and a user clicks on the buttons multiple times, the function (scheduled by a timeout) to flip the two divs never seems to execute. If it does execute, the display content is shown so quickly, it's as if the timeout was never called.
I've tried using a globally scoped state variable to control when button presses should be shut off, but that does not seem to work. Any advice or recommendations is welcome! Thanks!
Example
Imagine a 2 second window between each, the following diagram explains how it works with no onclick mouse events:
seconds 0 2 4 6
+----+----+----+
divs A B A B
NOTE: the top row are the 2 second intervals, the bottom row are the div flip events
with mouse on click events it should do something like this (A is scheduled to happen exactly at 4 seconds):
seconds 0 2 4 6
+----+----+----+
divs A BBBBBA B
what it currently does:
seconds 0 2 4 6....
+----+----+----+....
divs A BBBBBBBBBBB....
the scheduled A event never happens.
I think you missed to use clearTimeout or probably you are clearing the timer and not scheduling it back.
I quickly tried to simulate what you described. I am not sure if this is what you want, but check my
Old DEMO here (buggy when clicked multiple times, see the below link)
I am using setTimeout to call the function. Try using setInterval, which will be executed every n secs.
Edit: I fixed a bug which I missed in my previous demo, Please see the below link and let me know if it is close to what you want.
DEMO
Related
I am creating a MCQs quiz and there is a time for each question. I have also used onbeforeunload in my script to prevent the user from accidentally navigating away from the quiz page. But when that alert gets display my setInterval counter stop working. How can i make the countdown to not stop even if there is an alert?
To further explain my problem here is the FIDDLE
Browser dialogs are blocking. All script execution stops when they are open. You cannot change this behaviour.
Instead of starting with 90 seconds and trying to reduce that by 1 second every second, calculate the current date + the 90 seconds to get the end date. Then on each call of your setTimeout, calculate the current number of seconds until the end date.
The timer won't advance while the alert is visible, but it will skip to where it should be when the alert is dismissed.
A possible workaround could be that you declare a var timeCount = new Date() to store the time if a beforeunload() is called and use that to calculate passed time/missed seconds. But otherwise what Diodeus said is correct.
Im making some sort of a slideshow system, and I use JavaScript/jQuery/PHP to loop through different slides. This is all working good, but within the slides (that are dynamically loaded into a fullpage div), I also want to refresh sections of the slide (the slides are split up in several boxes).
I use SetInterval to reload the sections every x seconds, however, when the slide changes, and after a while the same slide appears, these SetIntervals stack up, causing the sections to reload way too many times.
I've tried to confirm whether the element still existed with:
var refreshBox = setInterval(function(){
if ($('#box_<php id>').length > 0){
//Ajax/Refresh code
}else{
clearInterval(refreshBox);
}
}, ".$boxes_data['box_refresh']."000);
But that didnt work. The intervals still act up when the same slide reappears.
Any solutions?
Thanks!
Already managed to fix it by creating a global array:
window.refreshBox=new Array();
Create interval within array:
refreshBox[".($boxes_data['box_id'])."] = setInterval(function(){
Delete interval from array:
clearInterval(refreshBox[".($boxes_data['box_id'])."]);
Possibly this has been discussed a zillion times and I'm over thinking this, but...
How does one create a 'blocking' jQuery animation?
I have a page which has a 'special' slider animation that executes the first time a user visits the site. But there is a 'normal' slider animation that fires every time the user visits the same page. Since both animations fire with document.ready() they both occur at the same time. What I -want- is for the first animation to fire and then when the user clicks a button to close the window -then- the second animation fires.
//pseudocode
jQuery( init );
function init() {
if(firstVisit) {
Animation1(); //Special. Only shows 1st visit to site
Animation2();
} else {
Animation2();
}
}
}();
Here's the site: http://jchmusic.com
I guess I can re-write the code for -both- so that the second one explicitly starts only when the user clicks the 'close' button on the first animation, but to -me- it would look much cleaner if I could just make the code on the first animation 'blocking'... ie. the second animation doesn't start until the first animation returns. I messed about with SetTimeOut and various 'loops' and all it does is hang the browser... I'm sure this has been mulled over many times.
Any ideas?
I have a page where I show a throbber when I navigate away from the page. Like <a onclick="throbber.show()"> on every link. When I now navigate back in Firefox, the throbber is still shown.
Is there any javascript event that is fired to the arriving webpage when I click back? Or one that is fired just when the webpage is changed to the new one? Or can I make my throbber more intelligent?
Thanks for any input!
put this in your html:
<form name="_browser"><input id="checker" value="1" type="hidden"></form>
and also this javascript:
function cacheCheck()
{
var checker = document.getElementById("checker");
if (checker.value == 2) return true;
checker.value = 2;
checker.defaultValue = 2;
return false;
}
function cacheReload()
{
if (cacheCheck()) location.reload(true);
}
and then call cacheReload when your page loads:
<body onload="cacheReload()">
Dldnh's answer inpired me to do some tests. I suspected that the body.onload() event would be called when going back and forth. So I created a simple testpage and found out that this is true in Firefox 10, IE7, IE 8, IE 9 and Chrome 17. Also jQuery(document).ready() will be called.
The very simple solution for hidind the throbber would therefore be either using
<body onload="hideThrobber()">
or using jQuery ready
jQuery(document).ready(function () {
hideThrobber();
};
to hide the throbber then. I implemented this and it seems to work fine on my page. Would be great if somebody with a similar problem could confirm this.
I also found this interesting Stackoverflow question. While it is a little outdated, the point that calling javascript on navigation back and forth slowing down the page is still true. But I would guess that todays JS-Engines are fast enough so this is not a real issue anymore.
If you can't turn off the throbber from the page you navigate to, there are a few things you can do. The trick is that the page will be left active, so you can start up some things before you leave, in the onclick. They aren't perfect though.
Start a timer. The timer will be running when you return to the page, so the timeout routine will be called, and you can switch the throbber off there.
Problem: if you set the timer interval too small, the timeout routine will be called before the user has actually left the page, and the throbber will stop. Or if you set the interval too large, it will take a while before the timeout routine kicks in after they have returned.
Add an event listener to the body that responds to the mousemove event, so that as soon as the user moves the mouse, the routine that turnes off the throbber will be called.
Problem: if the user clicks the browser's Back button, the mouse will be outside the window when the page is redisplayed, so the throbber will remain visible until the user moves the mouse into the window.
So, take your pick. Or do both. Just remember to clean up afterwards - stop the timer, remove the event listener.
I have a page that on a certain action makes an iframe visible and fills the iframe with some HTML (say for example a multi-select box and an ok button).
The OK button on the iframe has the onClick method defined kinda like this:
onClick="parent.hideIFrame();parent.processMultiSelectBox();"
When User clicks OK on the iframe (presumably after playing with the multi-select box), I'd like the iFrame to disappear immediately and then the selected values in the multi-select box can be processed. But this is not what's happening. The iFrame remains visible during the time the other function runs and disappears only after the second function finishes.
The hideIFrame function is pretty straightforward:
function hideIFrame() {
frmObj = document.all.iFrameID;
if(frmObj) {
frmObj.style.visibility = "hidden";
}
}
I've paraphrased the above function for clarity (removed some indicator variable assignments etc.)
The second function actually loops on all the options in the multi-select object and does stuff with it. This takes about a half a second and only after that is done, does my iFrame disappear. It is a little bothersome to see it linger for half a second when I click ok.
My question is whether there is some way I can make the darn thing disappear faster. Speaking in "classical C" lingo, is there a "flush" for the change in visibility to happen immediately?
I did notice that if I put an "alert" as the first line in my second function, the iframe disappears immediately but now it is the OK on the alert box that lingers for the time it takes the second function to finish.
Thanks.
EDIT: Based on DDaviesBrackett's answer, this is what I ended up doing:
The onclick in the iframe changed to:
onClick="parent.hideAndProcessMultiSelectBox(parm1, parm2);"
The hideAndProcessMultiSelectBox function was defined as:
function hideAndProcessMultiSelectBox( parm1, parm2 ) {
hideIFrame();
setTimeout( function() { processMultiSelectBox( parm1, parm2 ); }, 0 );
}
Voila.. no delay..
You've gotten to the root of your problem already; document reflow doesn't happen until the current JS thread is done (so as not to repaint lots of times during JS execution). You need to return control to the browser before doing your expensive processing.
The simplest way to achieve that, though it doesn't make for obvious code in the slightest, is to call processMultiSelectBox in a setTimeout with a delay of 0:
onClick="parent.hideIFrame();parent.setTimeout(parent.processMultiSelectBox,0);"
If you need to pass parameters to the thing you're setting a timeout on, you have two options: set a timeout on a string that evals to Javascript (bad, bad, very bad, horrible) or define an anonymous function that calls the one you're interested in:
onClick="parent.hideIFrame();parent.setTimeout(function(){parent.processMultiSelectBox(foo, bar, 'baz');},0);"
RSolberg's response may also help, though there's a difference between visibility:hidden and display:none.