jQuery append delay - javascript

Can someone explain why the rows in the console are appending all in one time? I want them to get append one by one. row is an array of strings in the program and here is the code:
var dodajRed = function(redenBroj) {
setTimeout(function() {
$('.console').append('<p>' + row[redenBroj] + '</p>');
}, 1500);
}
dodajRed(0);
dodajRed(1);
dodajRed(2);
I want the rows to appear one by one with 1500ms delay, but instead I get all rows appeared after 1500ms.

There are lots of ways to do this. One possible solution is adjust your timeout:
var dodajRed = function(redenBroj){
setTimeout(function () {
$('.console').append('<p>'+row[redenBroj]+'</p>');
}, (redenBroj + 1) * 1500);
}
dodajRed(0);
dodajRed(1);
dodajRed(2);
You could also setup a promise chain, but you'd need an external library or browser that supports ECMAScript 6.

Try using setInterval instead:
(function() {
var index = 0,
row = ["One", "Two", "Three"],
id,
stop = function() {
if (index > 2) {
clearInterval(id);
}
},
start = function() {
id = setInterval(function() {
$('.console').append('<p>' + row[index] + '</p>');
index++;
stop();
}, 1500);
};
start();
}());
JSFiddle

Related

Performance increase, code optimization of JQuery + json array code

By looking into many resources, I've figured out how to write following code, which process json array (data) and with 250ms delay shows result and adds class 'petstatusok' (or 'petstatusno') to existing element with class 'pet-items':
if (data.cat & data.cat !== 'null') {
setTimeout(function() {
$('.pet-items:nth-child(2)').addClass('petstatusok');
$('#label-cat').val((data.cat).trim());
}, 250);
} else {
setTimeout(function() {
$('.pet-items:nth-child(2)').addClass('petstatusno');
}, 250)
}
if (data.dog & data.dog !== 'null') {
setTimeout(function() {
$('.pet-items:nth-child(3)').addClass('petstatusok');
$('#label-dog').val((data.dog).trim());
}, 500);
} else {
setTimeout(function() {
$('.pet-items:nth-child(3)').addClass('petstatusno');
}, 500)
}
and so on... I have 24 blocks like this...
I do believe that there is a place to optimize the code...
My thoughts:
Is there any possibility to have a loop to reduce the number of code lines/increase performance?
Is there any possibility with setTimeout(function () to place it somewhere in code only once?
Any other opportunities?
Thank you!
You can use a simple forEach and calculate the child number and delay based on the index.
As #Ray said is his answer, null is not a string (unless your JSON is wrong) so you should remove the quotes and use && in this case. You actually don't even need to check for the null because it is falsy so if (data[pet]) will suffice.
I have assumed that cat is the first 'pet' child in .pet-items.
const pets = [
'cat',
'dog',
]
pets.forEach((pet, index) => {
const child = index += 2
const delay = (index + 1) * 250
if (data[pet]) {
setTimeout(function() {
$(`.pet-items:nth-child(${child})`).addClass('petstatusok');
$(`#label-${pet}`).val(data[pet].trim());
}, delay);
} else {
setTimeout(function() {
$(`.pet-items:nth-child(${child})`).addClass('petstatusno');
}, delay)
}
})
First create a function that can be called multiple times, with all the repeatable variables being used as input parameters - petType (name of the pet, which is a string) and index, which starts from 1.
function setStatusAndLabel(petType, index){
if (data[petType] && data[petType] !== null){
setTimeout(function() {
$('.pet-items:nth-child('+index+')').addClass('petstatusok');
$('#label-'+petType).val((data[petType]).trim());
}, 250);
} else {
setTimeout(function() {
$('.pet-items:nth-child('+index+')').addClass('petstatusno');
}, 500)
}
}
Next,
If data is an object with exclusively 24 items and nothing else, you could do a for loop through data like this:
var counter = 1;
for (var petType in data) {
if (data.hasOwnProperty(petType)) {
setStatusAndLabel(petType.toString(), counter++);
if (counter === 24){
// so that it doesn't continue to loop through the object's prototype methods, if any, after your work is done.
break;
}
}
}
OR
If data has other stuff in addition to the 24 items, then you need to specify what the required items are. You can do this with an array, then loop through it.
var requiredItems = ['cat', 'dog', 'cow',... (so on)];
requiredItems.forEach(function(petType, index){
setStatusAndLabel(petType, index);
});
(End)
By the way,
you should check for null like this data[dataType] !== null and not like this data[dataType] !== 'null'
& is the bitwise operator and && is the logical operator. You should use &&.

jQuery each function parseInt loop

My code is supposed to make a set of divs with classes that start with status- fade out then change the classes from ie status-1 to status-11 by adding 10 the number. Everything is working except that the parseint is looping and the classes are becoming status-179831, status-179832...
$(function disappear(){
$('[class^="status-"]').delay(5000).fadeOut(400)
$('[class^="status-"]').each(function(){
num = $(this).attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
$(this).attr("class", "status-"+num+"");
})
$('[class^="status-"]').delay(1000).fadeIn(400)
disappear();
})
To get your operations to work in sequential order, you need to use the completion function of your animations like this:
$(function (){
function runOne(item) {
item.delay(5000).fadeOut(400, function() {
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
.delay(1000).fadeIn(400, function() {runOne(item)});
});
}
// start all the animations
$('[class^="status-"]').each(function() {
runOne($(this));
});
})
Working demo: http://jsfiddle.net/jfriend00/k7aS7/
As your code was written, the two animations are asynchronous and your .each() loop or the next call to disappear() do not wait for the animations to finish. Using the completion functions like this triggers the next part of your sequence when the animation is done. You also want to always make sure you're using var in front of local variables to avoid accidentally making them global variables.
You can also synchronize a promise object which will guarantee that all the animations always start at the same time on each iteration:
$(function disappear() {
var all = $('[class^="status-"]');
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(disappear);
})
Working demo of this option: http://jsfiddle.net/jfriend00/SY5wr/
To restore the class names to the original class name after each iteration, you could do this:
$(function () {
// save original class names
var all = $('[class^="status-"]').each(function() {
$(this).data("origClassName", this.className);
});
function disappear() {
all.delay(5000).fadeOut(400, function() {
var item = $(this);
var num = item.attr('class').split('status-')[1];
num = parseInt(num, 10) + 10;
item.attr("class", "status-"+num+"")
item.delay(1000).fadeIn(400);
})
// when all animations are done, start the whole process over again
all.promise().done(function() {
// restore class names
all.each(function() {
this.className = $(this).data("origClassName");
})
// run it all again
disappear();
});
}
// start it
disappear();
})
Working demo: http://jsfiddle.net/jfriend00/hTmHL/

How to slow down a loop with setTimeout or setInterval

I have an array called RotatorNames. It contains random things but let's just say that it contains ["rotatorA","rotatorB","rotatorC"].
I want to loop through the array, and for each item i want to trigger a click event. I have got some of this working, except that the everything get's triggered instantly. How can i force the loop to wait a few seconds before it continues looping.
Here's what i have.
function Rotator() {
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
RotatorNames.forEach(function(entry){
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000);
});
}
You can run this to see what my issue is. http://jsfiddle.net/BxDtp/
Also, sometimes the alerts do A,C,B instead of A,B,C.
While I'm sure the other answers work, I would prefer using this setup:
function rotator(arr) {
var iterator = function (index) {
if (index >= arr.length) {
index = 0;
}
console.log(arr[index]);
setTimeout(function () {
iterator(++index);
}, 1500);
};
iterator(0);
};
rotator(["rotatorA", "rotatorB", "rotatorC"]);
DEMO: http://jsfiddle.net/BxDtp/4/
It just seems more logical to me than trying to get the iterations to line up correctly by passing the "correct" value to setTimeout.
This allows for the array to be continually iterated over, in order. If you want it to stop after going through it once, change index = 0; to return;.
You can increase the timeout based on the current index:
RotatorNames.forEach(function(entry, i) {
window.setTimeout(function() {
//Trigger that elements button.
var elemntBtn = $('#btn_' + entry);
elemntBtn.trigger('click');
}, 5000 + (i * 1000)); // wait for 5 seconds + 1 more per element
});
Try:
var idx = 0;
function Rotator() {
var RotatorNames = ["rotatorA", "rotatorB", "rotatorC"];
setTimeout(function () {
console.log(RotatorNames[idx]);
idx = (idx<RotatorNames.length-1) ? idx+1:idx=0;
Rotator();
}, 5000);
}
Rotator();
jsFiddle example
(note that I used console.log instead of alert)
Something like this should do what you're after:
function Rotator(index){
var RotatorNames = ["rotatorA","rotatorB","rotatorC"];
index = (index === undefined ? 0 : index);
var $btn = $("#btn_"+RotatorNames[index]);
$btn.click();
if(RotatorNames[index+1]!==undefined){
window.setTimeout(function(){
Rotator(index+1);
}, 500);
}
}

Javascript - how to update elements inner html?

I have something like this:
var stopwatch = function (item) {
window.setInterval(function () {
item.innerHtml = myInteger++;
}, 1000);
}
This code was supposed to display myInteger, but it is not updating values of item. Why (item is a div with text inside)?
There could be a lot of reasons (we need to see more of your code), but here is a working example:
var myInteger = 1,
stopwatch = function (item) {
window.setInterval(function () {
item.innerHTML = myInteger++;
}, 1000);
}
stopwatch(document.querySelector('div'));
Important changes:
Calling stopwatch (you probably do this)
- innerHtml +innerHTML (the case matters). You won't get an error for setting innerHtml; it will set that property and you won't notice anything.
Initialize myInteger.
http://jsfiddle.net/Q4krM/
Try this code :
var stopwatch = setInterval(function (item) {
item.innerHtml = myInteger++;
}, 1000);
This should work

How to stop all timeouts and intervals using javascript? [duplicate]

This question already has answers here:
javascript: Clear all timeouts?
(13 answers)
Closed 6 years ago.
I'm working on an ajax web appliation which contains many running timeouts and intervals. And now I need to clear all running timeouts and intervals sometimes. Is there a simple way to stop everything without need to store every timeout and interval ID and iterate through them and clear them?
Sometimes it's possible to save the timer Id / Handle to clear it later which would be the best solution. So this is a second best. But I wanted to give a better understanding of what's going on. It basically grabs the highest timer id and clears everything less than that. But it's also possible to clear other timers that you do not want to clear!
It is a little hackish, so be warned!
// Set a fake timeout to get the highest timeout id
var highestTimeoutId = setTimeout(";");
for (var i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
Updated answer after reading the duplicate I closed this question with -
It works and tested in Chrome on OSX
// run something
var id1 = setInterval(function() { console.log("interval", new Date())}, 1000);
var id2 = setTimeout(function() { console.log("timeout 1", new Date())}, 2000);
var id3 = setTimeout(function() { console.log("timeout 2", new Date())}, 5000); // not run
setTimeout(function() { console.log("timeout 3", new Date())}, 6000); // not run
// this will kill all intervals and timeouts too in 3 seconds.
// Change 3000 to anything larger than 10
var killId = setTimeout(function() {
for (var i = killId; i > 0; i--) clearInterval(i)
}, 3000);
console.log(id1, id2, id3, killId); // the IDs set by the function I used
NOTE: Looked at window objects that had a typeof number - funnily enough IE assigns an 8 digit number, FF a single digit starting with 2
Here is a workaround.
window.timeoutList = new Array();
window.intervalList = new Array();
window.oldSetTimeout = window.setTimeout;
window.oldSetInterval = window.setInterval;
window.oldClearTimeout = window.clearTimeout;
window.oldClearInterval = window.clearInterval;
window.setTimeout = function(code, delay) {
var retval = window.oldSetTimeout(code, delay);
window.timeoutList.push(retval);
return retval;
};
window.clearTimeout = function(id) {
var ind = window.timeoutList.indexOf(id);
if(ind >= 0) {
window.timeoutList.splice(ind, 1);
}
var retval = window.oldClearTimeout(id);
return retval;
};
window.setInterval = function(code, delay) {
var retval = window.oldSetInterval(code, delay);
window.intervalList.push(retval);
return retval;
};
window.clearInterval = function(id) {
var ind = window.intervalList.indexOf(id);
if(ind >= 0) {
window.intervalList.splice(ind, 1);
}
var retval = window.oldClearInterval(id);
return retval;
};
window.clearAllTimeouts = function() {
for(var i in window.timeoutList) {
window.oldClearTimeout(window.timeoutList[i]);
}
window.timeoutList = new Array();
};
window.clearAllIntervals = function() {
for(var i in window.intervalList) {
window.oldClearInterval(window.intervalList[i]);
}
window.intervalList = new Array();
};
It works for set/clear timeout/interval functions called after these lines are executed. Try and see it works:
setInterval('console.log(\'a\')', 1000);
setInterval('console.log(\'b\')', 500);
setInterval('console.log(\'c\')', 750);
setTimeout('clearAllIntervals()', 10000);
Proxying does the magic.
var noofTimeOuts = setTimeout('');
for (var i = 0 ; i < noofTimeOuts ; i++) clearTimeout(i);
var max = setTimeout(function(){ /* Empty function */ },1);
for (var i = 1; i <= max ; i++) {
window.clearInterval(i);
window.clearTimeout(i);
if(window.mozCancelAnimationFrame)window.mozCancelAnimationFrame(i); // Firefox
}
There's nothing built-in, but it's pretty easy to blast through all currently outstanding deferred execution functions by calling this clearAll() function:
function clearAll() {
for (var i = setTimeout(function() {}, 0); i > 0; i--) {
window.clearInterval(i);
window.clearTimeout(i);
if (window.cancelAnimationFrame) window.cancelAnimationFrame(i);
}
}
If you are in charge of the page you run, and can wrap the native deferred execution functions in wrappers that do the house keeping for of course equip each setter function with a corresponding .clearAll() too:
(function(deferFunctions) {
for (var setter in deferFunctions) (function(setter, clearer) {
var ids = [];
var startFn = window[setter];
var clearFn = window[clearer];
function clear(id) {
var index = ids.indexOf(id);
if (index !== -1) ids.splice(index, 1);
return clearFn.apply(window, arguments);
}
function set() {
var id = startFn.apply(window, arguments);
ids.push(id);
return id;
}
set.clearAll = function() { ids.slice(0).forEach(clear); };
if (startFn && clearFn) {
window[setter] = set;
window[clearer] = clear;
}
})(setter, deferFunctions[setter]);
})(
{ setTimeout: 'clearTimeout'
, setInterval: 'clearInterval'
, requestAnimationFrame: 'cancelAnimationFrame'
});
To try that it works, you could then try doing this, for instance, which will remain silent, as none of the callbacks end up firing before they're cancelled again:
// Some example timers of all types:
requestAnimationFrame(console.error);
setInterval(console.info, 1000, 'interval');
setTimeout(alert, 0, 'timeout');
// Now you can clear all deferred functions
// by execution type, whenever you want to:
window.setTimeout.clearAll();
window.setInterval.clearAll();
window.requestAnimationFrame.clearAll();
A little hack added to Gokhan Ozturk's answer
If you are using third party libraries which uses Timeouts and Intervals then they will also be cleared, so I added one parameter to notify function that this interval is to be push'ed or not to array.
window.setTimeout = function(code, delay, toBeAdded) {
var retval = window.oldSetTimeout(code, delay);
var toBeAdded = toBeAdded || false;
if(toBeAdded) {
window.timeoutList.push(retval);
}
return retval;
};
... // likewise for all functions.
You might be better off creating a scheduler. Take a look at this approach by Nader Zeid:
https://www.onsip.com/blog/avoiding-javascript-settimeout-and-setinterval-problems
It's an approach that help create some determinacy (because "the time interval argument of each of those functions really only establishes that the given function will execute after at least that amount of time. So a timed event can miss its target by literally any amount of time.").
Specifically, to the question you raise here, you can easily add and remove functions from the queue. While this response is long after the question was raised, hopefully it's helpful to any who find themselves struggling with Timeouts and Intervals.
You cannot clear any timeouts and intervals you don't know about.
You'd need something like getTimeoutList which isn't in the DOM3 spec, or even planned, AFAIK.
The previous proxying trick is nice, but if you have a lot of timeouts and intervals, I would not fill the arrays with consecutive numbers [1,2,3....], but with intervals. For example, instead of having [1,2,3,7,8,9], you would have maybe something like ['1-3','7-9'] or [[1,3],[7,9]], as a memory optimization. Of course this trick is only suited if you have a lot of timeouts and intervals and also if you would not stop arbitrary intervals that often.

Categories

Resources