I have the following part of code:
<script>
$(function() {
var ele = $('#clients');
var clr = null;
var rand = 0;
(loop = function() {
clearTimeout(clr);
(inloop = function() {
ele.html(rand+=1);
if(clr==1000) {
return;
}
clr = setTimeout(inloop, 5);
})();
})();
});
</script>
How can i create a second function which will count until another number in the same page? Tried to do a few tests without success..
I tried this:
<script>
$(function() {
var ele = $('#products');
var clr = null;
var rand = 0;
(loop = function() {
clearTimeout(clr);
(inloop = function() {
ele.html(rand+=1);
if(clr==151) {
return;
}
clr = setTimeout(inloop, 5);
})();
})();
});
</script>
But the first function counts only until 2.
Two problems:
You shouldn't use the return value of setTimeout like this - it's not guaranteed to be an incrementing integer, and even when it is, it's global to the page and you can't reset it. Since you're already keeping a count in rand, you can use that to terminate your loop instead of clr.
As pointed out by #putvande, you're overwriting a global inloop variable with your second loop, and they will therefore interfere with each other - you need to declare a local variable.
Also your clearTimeout isn't doing anything useful, and you don't actually need your clr variable...
$(function() {
var ele = $('#clients');
var rand = 0;
var inloop;
(loop = function() {
(inloop = function() {
ele.html(rand+=1);
if(rand==1000) {
return;
}
setTimeout(inloop, 5);
})();
})();
});
$(function() {
var ele = $('#products');
var rand = 0;
var inloop;
(loop = function() {
(inloop = function() {
ele.html(rand+=1);
if(rand==151) {
return;
}
setTimeout(inloop, 5);
})();
})();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="clients"></div>
<div id="products"></div>
Now you can extract the common code and reuse it:
function countTo(ele, count) {
var rand = 0;
var inloop;
(inloop = function() {
ele.html(rand += 1);
if(rand == count) {
return;
}
setTimeout(inloop, 5);
})();
}
$(function() {
countTo($('#clients'), 1000);
countTo($('#products'), 151);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="clients"></div>
<div id="products"></div>
It's because inloop is not defined anywhere and will therefore be defined on a global scope. In your second function, you override this variable. So your first function runs once, and then your second one will run until it stops.
So you should define the inloop inside your loop function:
...
(loop = function() {
var inloop;
clearTimeout(clr);
(inloop = function() {
...
Fiddle
But what you probably want is to rewrite it so you could just call your same functionality twice with some parameters.
Related
With an educational purpose I wrote the follow pice of code in JavaScript. The goal is to simulate a teletype machine and after the content is written the machine makes a pause before starts again.
var str = 'Some text';
strArray = str.split("");
window.onload = function teleType() {
var ctrl = 0;
var wrapId = document.getElementById("wrap");
var type = setInterval(function() {
wrapId.innerHTML += strArray[ctrl];
if (ctrl == strArray.length) {
wrapId.innerHTML = "";
ctrl = 0;
clearInterval(type);
}
ctrl++;
}, 2000);
setTimeout(teleType, 3000);
}
But with these intervals (mlliseconds) the machine begin to have an odd behavior. It jumps letters (index) or it starts from the begining without reach the end of the string (array). What is happening between the setInterval and the setTimeout ?
After setInterval is called you call setTimeout immediatelly.
As the result, you will trigger teleType before your interval completes.
You can move your setTimeout in the end of your interval:
var str = 'Some text';
strArray = str.split("");
window.onload = function teleType() {
var ctrl = 0;
var wrapId = document.getElementById("wrap");
var type = setInterval(function() {
wrapId.innerHTML += strArray[ctrl];
if (ctrl == strArray.length) {
wrapId.innerHTML = "";
ctrl = 0;
clearInterval(type);
setTimeout(teleType, 300);
}
ctrl++;
}, 200);
}
<div id="wrap"></div>
Now, teleType function runs interval, and when it finishes writing text it clears HTML content and tells browser to run teleType again in 2 seconds.
By the way, you don't need to set ctrl to 0, because it is local and will be reset anyway.
A sample function which outputs the text to console,
function showTeleText(text, repeat) {
var textByChar = text.split(''),
intermText = '',
textPos = 0;
var interval = setInterval(function () {
intermText += textByChar[textPos++]
console.log(intermText);
if (textPos >= textByChar.length) {
clearInterval(interval);
if (repeat) {
setTimeout(function () {
showTeleText(text, repeat);
}, 2000);
}
}
}, 500);
}
on window.load call showTeleText('Some text!', true/false) like,
window.load = function() {
showTeleText('Some text!', true);
}
I am using the Peity js plugin to create donut charts on my page. I am trying to animate the chart for each of the .foo elements:
<span class="foo" data-value="10"></span>
$('.foo').each(function () {
var updateChart = $(this).peity('donut');
var text = "";
var i = 0;
function myLoop() {
setTimeout(function () {
text = i + "/12";
updateChart.text(text)
.change()
i = i + 0.2;
var maxValue = $(this).data("value");
if (i <= maxValue) myLoop();
}, 0.5)
}
myLoop();
});
However it won't work for some reason with no errors in console. If I remove the $('.foo').each(function () { ... } part (and all "this" instances) the code will work. Thanks in advance for any help.
The problem is the context inside the timer handler, the easiest fix here is to use a closure variable
$('.foo').each(function () {
var $this = $(this);
var updateChart = $this.peity('donut');
var text = "";
var i = 0;
function myLoop() {
setTimeout(function () {
text = i + "/12";
updateChart.text(text)
.change()
i = i + 0.2;
var maxValue = $this.data("value");
if (i <= maxValue) myLoop();
}, 0.5)
}
myLoop();
});
When the timeout callback is executed, the this context refer to window, because you are actually calling window.setTimeout method.
Try this:
$('.foo').each(function () {
var updateChart = $(this).peity('donut');
var text = "";
var i = 0;
function myLoop() {
setTimeout($.proxy(function () {
text = i + "/12";
updateChart.text(text)
.change()
i = i + 0.2;
var maxValue = $(this).data("value");
if (i <= maxValue) myLoop();
},this), 0.5)
}
myLoop();
});
I'm trying to clear an interval when the user hovers over an element and then start it up again when they hover off an element. I think this is a closure but I'm not sure, hopefully my code will make sense what I'm trying to do.
var rotatorInterval = function(elem){
var interval = setInterval(function(){
var active = elem.find('.dot.active');
if(active.is('.dot:last-of-type',elem)){
elem.find('.dot').first().click();
}else{
active.next().click();
}
},6000);
interval;
return interval;
};
if($('.rotator').length){
$('.rotator').each(function(){
var self = $(this);
rotatorInterval(self);
self.find('.slide, .dot').on('mouseenter',function(){
console.log('hovered');
clearInterval(interval);
});
});
}
I tried returning the interval from that closure but when I hovered it said interval (the name of the variable I returned) is not defined, so it's like it didn't return it or something.
You just have to actually return the interval reference somewhere
var rotatorInterval = function (elem) {
var interval = setInterval(function () {
var active = elem.find('.dot.active');
if (active.is('.dot:last-of-type', elem)) {
elem.find('.dot').first().click();
} else {
active.next().click();
}
}, 6000);
return interval;
};
if ($('.rotator').length) {
$('.rotator').each(function () {
var self = $(this);
var return_interval = rotatorInterval(self);
self.find('.slide, .dot').on('mouseenter', function () {
clearInterval(return_interval);
});
});
}
I have several URLs in my array and I want to run it one by one,
but when I run it in a loop, it executes all at the same time and does not wait.
Here is what I tried:
<html>
<head>
<script>
function work(){
var otherStoryLinksArray = [];
otherStoryLinksArray[0] = 'http://google.com';
otherStoryLinksArray[1] = 'http://www.yahoo.com';
otherStoryLinksArray[2] = 'http://gmail.com';
for(var i=0;i<3;i++){
var openWindow = window.open(otherStoryLinksArray[i]);
setTimeout(function(){openWindow.close();},3000);
}
}
</script>
</head>
<body onload=work();>
</body>
</html>
I want it to open one URL, wait for 30 secs, close the popup, and then start another URL.
Waiting for your reply guys. Any help would be appreciated thanks...
Code: http://jsfiddle.net/WgR4y/1/
Demo: http://jsfiddle.net/WgR4y/1/show/ (make sure you disable popup blocker)
Works for unlimited number of URLs in array.
var otherStoryLinksArray = [
'http://google.com',
'http://www.yahoo.com',
'http://gmail.com'
],
timeToCloseWindow = 3000;
function work() {
if(otherStoryLinksArray.length==0) return;
var url = otherStoryLinksArray.shift();
var openWindow = window.open(url);
setTimeout(function () {
openWindow.close();
work();
}, timeToCloseWindow);
}
work();
You need to stagger your setTimeout calls and since setTimeout uses ms, 30 s = 30000 ms:
function work () {
var otherStoryLinksArray = [];
otherStoryLinksArray[0] = 'http://google.com';
otherStoryLinksArray[1] = 'http://www.yahoo.com';
otherStoryLinksArray[2] = 'http://gmail.com';
for(var i=0; i<3; i++) {
var openWindow;
setTimeout(function () {
openWindow = window.open(otherStoryLinksArray[i]);
}, 30000 * i); //Open this window
setTimeout(function () {
openWindow.close();
}, 30000 * i + 30000); //Close it 30 seconds from "now"
}
}
Use set interval instead of for-loop
function work(){
var otherStoryLinksArray = [];
otherStoryLinksArray[0] = 'http://google.com';
otherStoryLinksArray[1] = 'http://www.yahoo.com';
otherStoryLinksArray[2] = 'http://gmail.com';
var myVar=setInterval(function(){myTimer()},3000);
var i=0;
var openWindow;
function myTimer()
{
if(openWindow != null)
openWindow.close();
if(i < 3)
{
openWindow = window.open(otherStoryLinksArray[i]);
i++;
}
else
clearInterval(myVar);
}
}
var otherStoryLinksArray = [
'http://google.com',
'http://www.yahoo.com',
'http://gmail.com'];
var i = 0;
var openedWindow = null;
function loop(){
openedWindow && openedWindow.close();
if(otherStoryLinksArray[i]){
var openedWindow = window.open(otherStoryLinksArray[i]);
i++;
setTimeout(loop,30000);
}
}
<span id="ccc">10</span> <span id="start">start</span> <span id="stop">stop</span>
$('#start').click(function(){
var c = $('#ccc').text();
var inter = setInterval(function() {
c--;
$('#ccc').text(c);
}, 1000);
});
$('#stop').click(function(){
clearInterval(inter);
});
how i must rewrite this for correctly use STOP?
LIVE: http://jsfiddle.net/c3hZh/
inter needs to be in-scope for both functions. Wrap both functions with a closure so that you can avoid polluting the global namespace with a new variable.
(function ($) {
var inter;
$('#start').click(function(){
var c;
c = parseInt($('#ccc').text()); //make sure you're getting a numeric value
//don't forget to clear any existing interval before setting a new one:
if (inter) {
clearInterval(inter);
}
inter = setInterval(function() {
c--;
$('#ccc').text(c);
}, 1000);
});
$('#stop').click(function() {
clearInterval(inter);
});
}(jQuery));
inter is a local variable.
It doesn't exist outside your callback.
You need to use a global variable.
var inter = 0;
$('#start').click(function(){
var c = $('#ccc').text();
inter = setInterval(function() {
c--;
$('#ccc').text(c);
}, 1000);
});
$('#stop').click(function(){
clearInterval(inter);
});