I've seen this problem asked before, but all the suggestions I've tried as well as some experimentation on my own have failed.
If I run the following code using Javascript, the textarea will display only the last value of i (5). If I use the alert that is commented out, then it works.
I've tried using timeout, invterval, date and time delays and even loops to delay processing but none works unless I use an alert as used in the code below when not commented out. I know some delays still allow processing to continue. I've also tried passing variables to other functions to display in the textarea from there since it appears the textarea displays the last value after exiting the function.
Any suggestions how I can get the textarea to update with each iteration so the numbers 1 through 5 are displayed one at a time?
And I'm curious why the alert will work when other methods of pausing the action won't.
Thanks.
function Go(){
var i = 0;
for(i=0; i<6; i++){
alert("This allows textarea to update with each iteration");
document.getElementById("ta").value = "";
document.getElementById("ta").value = i;
}
}
<textarea id="ta" name="display" rows="15" cols="50"></textarea>
<br /><INPUT TYPE="button" VALUE="START" onClick="Go()">
Here's another possible example using recursion:
function Go(counter){
if (counter > 5){
return;
} else {
document.getElementById("ta").value = counter;
window.setTimeout(function(){ Go(++counter) }, 500);
}
};
Go(1);
If you just passed your function as the callback to a timer, the timer would have waited the specified duration, then executed the function - which runs through all the iterations without any delays between. You have to wait between function calls (or iterations) to see the number increase. Hope that helps :)
Here is an example using scope and setTimeout
function Go(){
var i = 0,
fn = function () {
if (i >= 6) return;
document.getElementById("ta").value = i;
++i;
window.setTimeout(fn, 500);
};
fn();
}
If you want to display the numbers one at a time, use a simple interval function, then clear it when you're done:
var interval = setInterval(function() {
var textArea = document.getElementById("ta");
var currentVal = textArea.value || -1;
currentVal == 5 ? clearInterval(interval) : textArea.value = ++currentVal;
}, 2000);
And your onClick: onClick="interval">
Demo: http://jsfiddle.net/at4aX/
Some of those other methods actually spawn background threads so that forward processes can continue unabated. You need something that will pause the run until the specified time is up, or alternatively run as an event-driven mechanism.
window.setTimeout() works great for this. I used jquery to locate the objects, and wait for domready in my example. You're under no obligation to do this, I just find it easier. Fiddle here.
$(function() {
var iterations = 6;
var burndown = function() {
var value = $("#fooinput").val() - 1;
$("#fooinput").val(value);
if( value > 0) {
window.setTimeout(burndown,1000);
} else {
$("#clickme").removeAttr("disabled");
}
}
$("#clickme").click(function() {
$("#clickme").attr("disabled","true");
$("#fooinput").val(iterations);
window.setTimeout(burndown,1000);
});
});
Thanks for all your answers. I should have checked in earlier. Spent all day on this.
I'm new at Javascript and did come up with something that works on my own but it ain't
pretty. I want to learn to use Javascript correctly so I'll look over your
responses and compare. Seems I should be able to consolidate the functions I came up
with below or just learn from your suggestions posted here. I guess I should become
familiar with jquery, Ajax, etc. as I saw that used a lot in my searching for an
answer.
<body>
<textarea id="ta" name="testinput" rows="15" cols="50"></textarea>
</body>
<script language="javascript" type="text/javascript">
var i = 0;
document.getElementById('ta').innerHTML = i;
setTimeout(Test1, 3000);
function Test1(){
i++;
document.getElementById('ta').innerHTML = i;
if(i<4){ //TEXTAREA WILL STOP AT 5
setTimeout(Test2, 3000);
}
}
function Test2(){
i++;
document.getElementById('ta').innerHTML = i;
setTimeout(Test1, 3000);
}
</script>
Related
My Son is trying to get this code to work as he applying for College course. He neeeds to give an explanation of how it works from the Youtube example. The problem he has & I have is we cant get the code to run.
Youtube example he is working from.
https://www.youtube.com/watch?v=u_6CqjQ-L8Q&authuser=0
This should be a simple countdown timer from 10 to zero - any ideas what I am doing wrong. Using Notepad++ to create the example & run.
<script type="text/javascript">
function countdown(secs,elem) {
var element = document.getElementById(elem);
element.innerHTML = "Please wait for "+secs+" seconds";
if(secs<1){
clearTimeout(timer);
element.innerHTML = '<h2>Countdown Complete!</h2>';
element.innerHTML += 'Click here now';
}
secs = secs--;
var timer = setTimeout('countDown('+secs+',"'+elem+'")',1000);
}
</script>
<div id="status"></div>
<script type="text/javascript">countdown(10,"status");</script>
Some issues:
secs = secs-- will not modify secs. Just secs-- would be ok.
The spelling of the function is not consistent
Some more issues, which are also present in the link you provided:
When the timer is supposed to stop, the code still continues to call setTimeout
This code uses a bad practice to pass a string to setTimeout while it is perfectly possible to pass a function.
calling clearTimeout is useless where it happens, as at that moment there is no pending one.
Working code:
function countdown(secs,elem) {
var element = document.getElementById(elem);
if(secs<1){
element.innerHTML = '<h2>Countdown Complete!</h2>'
+ 'Click here now';
return; // <---- don't call setTimeout again
}
element.textContent = "Please wait for "+secs+" seconds";
// Spelling of countdown is important. Don't use string, but bind:
setTimeout(countdown.bind(null, secs-1, elem), 1000);
}
countdown(10, 'status');
<div id="status"></div>
<script>
var fn = function(url){
// bla bla bla...
};
</script>
<input type="button" onclick="fn()" value="Execute">
<input type="button" onclick="???" value="Abort">
Just like above, when a user click on the “Execute” button, the fn() function will be executed. Suppose the fn() function will run for a very very long time, and if the user want to stop the execution of this function midway, how should I do?
Functions in JavaScript are blocking -- which means that everything[1] freezes as the function runs. The screen doesn't redraw, mouse clicks are not processed, keyboard events are not processed.
Nothing happens until the function is done.
The only way to counter this is to use async coding to run your code in small, bite-sized chunks.
There are a number of tools to use, including:
setTimeout and keeping an array index
How to make non-blocking javascript code?
generator functions (not node specific)
What are ES6 generators and how can I use them in node.js?
I'd recommend looking at the async tools then asking another question on how to make your function non-blocking.
[1] For the purposes of this discussion
You can set second input type="button" disabled attribute; create a variable referencing deferred object; remove disabled attribute at input type="button" when deferred object is created; call deferred.reject() with new Error() as parameter at click of second input type="button"
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<script>
var ajax, d;
function fn(event, url){
// bla bla bla...
ajax = new $.Deferred(function(dfd) {
d = dfd;
$("input[value=Abort]").removeAttr("disabled")
setTimeout(function() {
dfd.resolve("complete")
}, Math.random() * 10000)
});
ajax.then(function(complete) {
console.log(complete)
}, function(e) {
console.log(e)
})
};
</script>
<input type="button" onclick="fn(event)" value="Execute">
<input type="button" onclick="d.reject(new Error('aborted'))" value="Abort" disabled>
Generally not, you can't. At least I don't think you can. But you can and should write your functions in such way that they don't block your UI.
UI and JavaScript are using one thread, so if very long function is running in JavaScript user cannot use UI. So click event would not be handled anyway. Instead what you want is to split long computation in parts using setTimeout (or some library that uses it internally).
Then check for aborting condition. Very simplistic example of such thing is in snippet below.
var abort = false;
var target = document.getElementById('target');
function veryLongFunction(step) {
step = step || 0;
if (abort) {
return;
}
target.innerHTML = target.innerHTML + '<br>' + step;
window.setTimeout(veryLongFunction.bind(null, step + 1), 1000);
}
document
.getElementById('start')
.addEventListener('click', function () {
veryLongFunction(0);
});
document
.getElementById('stop')
.addEventListener('click', function () {
abort = true;
});
<button id="start">start</button>
<button id="stop">stop</button>
<div id="target"></div>
You can break the function into parts and stall the parts with a timer. A timer breaks up the event loop to allow something like a button click to update a variable, like setting abort = true.
In the broken up function, check if the variable is updated to indicate you should abort. Return if it is, otherwise keep running the function.
There are different ways to abort ajax requests. You can set up a pool of open requests and a function for your onclick event to abort them.
Something like this with jquery:
var ajaxPool = [];
$.ajaxSetup({
beforeSend: function(jqXHR) {
ajaxPool.push(jqXHR); // keep track of active requests
},
complete: function(jqXHR) {
var index = ajaxPool.indexOf(jqXHR);
if (index > -1) {
ajaxPool.splice(index, 1); // remove completed requests
}
}
});
//the function to run onclick:
function abortAllAjax () {
for (var i = 0; i < ajaxPool.length; i++) {
ajaxPool[i].abort();
}
ajaxPool = [];
};
I'm pretty sure there's not, but if there would, it would be wrong.
In a single threaded language, a correct solution could be to check a stop flag after doing some work. If the flag (a property or a global variable) becomes true, the algorithm does whatever it has to do to stop and the function returns.
If the algorithm is long or contains a loop, it would look like this:
var running=true;
var fn = function(url){
while(1) {
if(!running) return;
// bla bla bla...
}
};
If you meant an ajax call that would take long to complete, you can abort it with abort():
var xhr=$.ajax(...);
...
xhr.abort();
I utilized this resource to structure my code: http://www.w3schools.com/jsref/met_win_clearinterval.asp
var intervalID = setInterval(function(){ ogpeWrapper() }, 10);
function ogpeWrapper() {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
}(jQuery);
function myStopFunction() {
if (document.getElementById('colWrapperContainer')) {
clearInterval(intervalID);
setIntervalID = undefined;
}
}
My ogpeWrapper function is running, but the clearInterval function is not.
Basically, once $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll(''); runs, I want the interval to stop running it.
Edit - 12:24pm CST:
This is the base code I utilize to wrap the listed elements -
(function($) {
$("#breadcrumbAds, #breadcrumbWrapper, #containerTopParsys, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
})(jQuery);
This code works, but it doesn't process the change until after the DOM has completely loaded. I need the function to work as soon as those elementals are all available. So I need to use a setInterval to process the function, then clear the interval once the function is processed.
If anyone knows of another way to do this, besides a setIterval, please let me know.
You need to create a definite if else condition within the variable so you know exactly when it will start and when it will stop. Also, because the minimum millisecond interval timing is not consistent across browsers, although you want it to detect really fast, I would recommend a "safer" number and use 100 as the minimum instead. The .length method is a handy little way for you to check if an element is on a page; You can use it as a pseudo dynamic true/false conditional. Lastly, in your .wrapAll() tag, I swapped your single and double quotes, as it is best practice to do such.
var colWrapper = setInterval(function(){
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll("<div id='colWrapperContainer'></div>");
}
}, 100);
Here is a working example for your reference Wrap Example
Update:
Example for putting the script inside the <body> tag (no window.load/document.ready) so that it runs independently as soon as it is loaded.
<script type="text/javascript">//<![CDATA[
//http://stackoverflow.com/questions/33483000/clearinterval-function-not-clearing-setinterval-function/33483267#33483267
//Auto Wrap Solution
//Alexander Dixon [11-02-2015]
var wrapThese = $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper");
var colWrapper = setInterval(function () {
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
wrapThese.wrapAll('<div id="colWrapperContainer"></div>').addClass('success');
}
}, 100);
//]]>
</script>
I have a button that takes 2 functions onclick. Here is my button:
<button id="btnNext" onclick="increment(); Next();">Next</button>
The increment() function works as intended on the first click but the Next() function does not. It does work as intended after first click. If I remove the increment() function, the Next() function works on first click. I have tried combining the functions but it gives me the same result.
The Next() function moves to the next form and the increment() function moves the scrollbar slider to the desired position.
Here are my functions:
var Next = function () {
UserVM.Model.MoveCurrentToNext();
}
var increment = function () {
if (lastScroll < 240) {
lastScroll += 40;
}
scrollpos.scrollTop = lastScroll;
}
Does anyone know what the reason is for this?
UPDATE: I added an alert to the Next() function. Now when I trigger the button it shows the next form when the alert box pops up but when I click ok, it returns to the previous form. This only happens when I click the button for the first time. Any reason for this? Anyway to solve it?
I don't know why are you using two separate functions for a single onclick unit because if you want to do both the operations why don't you call the form redirection code in the same function.
var increment = function ()
{
if (lastScroll < 240)
{
lastScroll += 40;
}
scrollpos.scrollTop = lastScroll;
//form navigation
UserVM.Model.MoveCurrentToNext();
}
HTML
<button id="btnNext" onclick="increment();">Next</button>
You can try this:
var Next = function () {
alert("This is Next Function");
}
var increment = function () {
alert("This is Increment Function");
Next();
}
<button id="btnNext" onclick="increment()">Next</button>
I have a feeling it is a timing issue. Add a slight delay to give the scroll position to change. (Just an educated guess);
var Next = function () {
window.setTimeout(UserVM.Model.MoveCurrentToNext, 100);
}
var increment = function () {
if (lastScroll < 240) {
lastScroll += 40;
}
scrollpos.scrollTop = lastScroll;
}
remove the onclick attr and put this in your code js:
$(document).ready(function(){
$(document).on("click","#btnNext",function(){
Next();
increment();
});
});
All provided answer work but I think this one is closer to what you need (without using other JS libraries neither making the functions to depend on others)
<button id="btnNext" onclick="(function(){increment();setTimeout(next, 100)})()">Next</button>
Note that this solution is wrapping the call of both increment() and newxt() function inside another anonymous function.
I feel dumb. I figured it out, should have figured it out way earlier. I have the variable lastScroll in another function, so I just change it to the variable position - var position = 0;. Now it works. Sorry for wasting everyone's time. I'll leave this question up just in case any of your answers help someone else out.
I have come up with the following code, which allows users to view a page with a movie embed for 30 seconds before redirecting them away from the page. Additionally, they can click a link to hide the div with this countdown. What I need help with is canceling the redirect (stopping it from happening) if that link is clicked, so users can continue to watch the full movie. Thanks in advance for your help!
Javascript:
<script type="text/javascript">
var settimmer = 0;
$(function(){
window.setInterval(function() {
var timeCounter = $("b[id=show-time]").html();
var updateTime = eval(timeCounter)- eval(1);
$("b[id=show-time]").html(updateTime);
if(updateTime == 0){
window.location = ("redirect.php");
}
}, 1000);
});
</script>
<script type="text/javascript">
$(document).ready(function(){
$(".slidingDiv").show();
$(".show_hide").show();
$('.show_hide').click(function(){
$(".slidingDiv").slideToggle();
});
});
</script>
HTML:
<div id="my-timer" class="slidingDiv">
You have <b id="show-time">30</b> seconds to decide on this movie.
Yes, I want to watch this one!
</div>
setInterval returns a value you can use to cancel the interval timer via clearInterval. So:
$(function(){
// +--- Remember the value from `setInterval
// |
// v
var timerHandle = window.setInterval(function() {
var timeCounter = $("b[id=show-time]").html();
var updateTime = eval(timeCounter)- eval(1);
$("b[id=show-time]").html(updateTime);
if(updateTime == 0){
window.location = ("redirect.php");
}
}, 1000);
// + Hook up a handler for the link that uses the handle to clear it
// |
// v
$("selector_for_the_link").click(function() {
clearInterval(timerHandle);
timerHandle = 0;
});
});
Note that I've put the variable inside your ready function, so it isn't a global.
Off-topic: You don't need or want to use eval in the above (in fact, you virtually never want to use eval at all, for anything). If you want to parse a string to make a number, use parseInt (and there's never any reason to eval a literal like 1). So this line:
var updateTime = eval(timeCounter)- eval(1);
becomes
var updateTime = parseInt(timeCounter, 10) - 1;
(The 10 means the string is in decimal — e.g., base 10.)
You need to use the clearInterval method.
Maybe you can use setTimeout() to do so rather than setInterval().Here is a sample.