setInterval & setTimeout executing at the wrong time - javascript

I want to change the background image using setInterval and setTimeout every x seconds but im strugling a bit. The problem is that the timer is not working as supposed to. It changes the images instantly.
let images = ['background1.jpg', 'background2.jpg','background3.jpg'];
let i = 0;
$("main").css("background-image", 'url(' + images[i] + ')');
setInterval(function(){
setTimeout( function() {
if(i == 0){
i++;
$('main').css({
'background-image': 'url(' + images[i] + ')',
'background-size': 'cover'
});
}
},3000);
setTimeout( function() {
if(i == 1){
i++;
$('main').css({
'background-image': 'url(' + images[i] + ')',
'background-size': 'cover'
});
}
},3000);
setTimeout( function() {
if(i == 2){
i = 0;
$('main').css({
'background-image': 'url(' + images[i] + ')',
'background-size': 'cover'
});
}
},3000);
}, 3000);

Get the main element (Or the target)
Declare the CSS background-size': 'cover for DRY (Don't Repeat Yourself) coding.
Show the first image, and increase i to show the next one in the "loop"
// The images indexes holder
let i = 0;
// Set the first image (i = 0 for now)
el.style.backgroundImage = `url(${arr[i]})`;
// increase i, to prevent showing the first image twice (for the first 6 seconds).
i++;
Finally, change the background-image every 3 sec. If reaches the last index, set to the first. And repeat...
The Code:
//var images = ['background1.jpg', 'background2.jpg','background3.jpg'];
var images = ['https://www.w3schools.com/html/img_girl.jpg',
'https://www.w3schools.com/html/pic_trulli.jpg',
'https://www.w3schools.com/html/img_chania.jpg']
var main = document.querySelector("main");
const backgroundSlider = (el, arr) => {
let i = 0;
el.style.backgroundImage = `url(${arr[i]})`;
i++;
setInterval(() => {
el.style.backgroundImage = `url(${arr[i]})`;
i++;
i == arr.length ? i = 0 : '';
}, 3000);
};
backgroundSlider(main, images);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
main {
background: center / contain no-repeat;
height: 100vh;
}
<main></main>

Your code will not work because setTimeout is async. Your 3 updates are not done like 3s,6s,9s.
The three setTimeout statements are read in stepbystep order and the functions inside them are requested(in simple terms) to be run after 3s by each one of them.
They are all done after ~3s (almost 3s) delay.
So, in the end you see the last function run which has i=0 and resets to the first image.
Edit: similar solution has been posted already. This one uses jQuery.
//This will run every 3s.
setInterval(function(){
i = (i+1)%3;
$('main').css({'background-image': 'url(' + images[i] + ')',
'background-size': 'cover'
});
}, 3000);

Related

How can I change background image in 1 second for only one time

I'm trying to change my background only one time after 1 second of loading. Then Second Image will be show.
I just want to show the first image only for 1st one second then want to show second image.
HTML
<div id="image-head" class="image-head">
</div>
CSS
.image-head {
background-image:url(background_image_1.png);
background-size: cover;
background-repeat: no-repeat;
background-position: top center;
}
JS
var images = [
"http://example.com/wp-content/uploads/2019/05/background_image_2.jpg"
]
var imageHead = document.getElementById("image-head");
var i = 1;
setInterval(function() {
imageHead.style.backgroundImage = "url(" + images[i] + ")";
i = i + 1;
if (i == images.length) {
i = 0;
}
}, 1000);
Please let me know how can I do it.
Thanks!
You need to use setTimeout instead of setInterval
And you don't even need that array
setTimeout(() => document.getElementById("image-head").style.backgroundImage = `url("http://example.com/wp-content/uploads/2019/05/background_image_2.jpg")`, 1000);
You should replace
setInterval(function() {
imageHead.style.backgroundImage = "url(" + images[i] + ")";
i = i + 1;
if (i == images.length) {
i = 0;
}
}, 1000);
by
setTimeout(function() {
imageHead.style.backgroundImage = "url(" + images[i] + ")";
i = i + 1;
if (i == images.length) {
i = 0;
}
}, 1000);
The setInterval() method, offered on the Window and Worker interfaces, repeatedly calls a function or executes a code snippet, with a fixed time delay between each call. It returns an interval ID which uniquely identifies the interval, so you can remove it later by calling clearInterval().
The setTimeout() method of the WindowOrWorkerGlobalScope mixin (and successor to Window.setTimeout()) sets a timer which executes a function or specified piece of code once the timer expires.
See document
#DominikMatis has the correct answer, but I wanted to help clean the code up a bit.
var image = "http://example.com/wp-content/uploads/2019/05/background_image_2.jpg";
var imageHead = document.getElementById("image-head");
setTimeout(function() {
imageHead.style.backgroundImage = "url(" + image + ")";
}, 1000);
This makes more sense since you're only replacing the image once, with a single image. What you had before would work great for replacing several images at a specified time interval.

function firing multiple times when scrolling fast

First of all, I'm not very advanced at code and tend to only do this part time so please excuse all terrible/ugly code! I appreciate there are already some solutions out there but I can't seem to make any of them work with my code so would really appreciate some help!
I'm using isotope grid and trying to setup an infinite scroll. I want to load 10 images at a time when the user scrolls to the bottom by taking these images from an array and appending them to a temp div.
This is working perfectly when scrolling slowly, but as soon as you scroll quickly the function seems to fire multiple times, it gets a little glitchy and loads lots of images at once.
$(window).scroll(function() {
var scrollTop = $(window).scrollTop();
var windowHeight = $(window).height();
var docuHeight = $(document).height();
if(scrollTop + windowHeight == docuHeight){
nextTenImages = imagesData.splice(0,10);
var content = ""
for (var i = 0; i < nextTenImages.length; i++) {
content +=
"<div class='box " + nextTenImages[i]["type"] + "'" + ">" +
"<div class='box-wrapper'>" +
"<img src='" + nextTenImages[i]["src"] + "' />" +
"</div>" +
"</div>"
};
$('body').append('<div id="temp-load"><div id="grid"></div></div>');
$('#temp-load > #grid').append(content)
$('#temp-load > #grid').children().css({
opacity: 0
});
var toAdd = $('#temp-load > #grid').html();
$container.isotope('insert', $(toAdd), function(){
$container.children().css({
opacity: 1
});
$('#temp-load').remove();
});
}
});
Make a single timeout to run the callback. This may avoid the function from executing multiple times.
var timer;
function scrollEvt() {
/* scroll actions */
}
$(window).scroll(function() {
/* clear the old timeout */
clearTimeout(timer);
/* wait until 400 ms for callback */
timer = setTimeout(scrollEvt, 400);
});
Using other ways may result in problems (like comparing (window.performance || Date).now())...
Unbind that specific scroll event till your delayed operation is completed to prevent accumulating more of the event triggers which create the duplication behaviour as in your case.
var winCached = $(window),
docCached = $(document)
var currLeng = 0;
function addContent() {
dettachScrollEvent();
setTimeout(function() { //this timeout simulates the delay from the ajax post
for (var i = currLeng; i < currLeng + 100; i++)
$('div').append(i + '<br />');
currLeng = i;
console.log("called loader!");
attachScrollEvent();
}, 500);
}
function infiNLoader() {
if (winCached.scrollTop() + winCached.height() > docCached.height() - 300) {
addContent();
//alert("near bottom! Adding more dummy content for infinite scrolling");
}
}
function attachScrollEvent() {
winCached.scroll(infiNLoader);
}
function dettachScrollEvent() {
winCached.unbind('scroll', infiNLoader);
}
addContent();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>

Sequentially highlighting divs using javascript

I'm trying to create kind of runway of lights and here's what it looks like now
http://jsfiddle.net/7NQvq/
var divs = document.querySelectorAll('div');
var index = 0;
setInterval(function(){
if(index > divs.length+20){
index = 0;
}
if(divs[index-1]){
divs[index-1].className = '';
}
if(divs[index]){
divs[index].className = 'active';
}
index++;
}, 50);
What I don't like about it is that it's completely inflexible and hard to adjust. Furthermore it also runs additional 20 empty cycles which is wrong. Is there a better way to achieve it (preferrably pure JS)?
It seemes that there must be some combination of setInterval and setTimeout but I just can't make it work.
I've made some adjustments to use a CSS animation rather than messing around with transitions and class toggling.
Updated Fiddle
All the JavaScript does now is define the animation delay for each dot.
You can adjust:
The animation delay - I just have i/10, but you could make it i/5, i/20... experiment!
The animation duration - it's set to 1s in my Fiddle, but try shorter and longer to see what happens
The 50% that indicates when the light has faded out
How about
function cycle(selector, cssClass, interval) {
var elems = document.querySelectorAll(selector),
prev = elems[0],
index = 0,
cssClassRe = new RegExp("\\s*\\b" + cssClass + "\\b");
if (elems.length === 0) return;
return setInterval(function () {
if (prev) prev.className = prev.className.replace(cssClassRe, "");
index %= elems.length;
elems[index].className += " " + cssClass;
prev = elems[index++];
}, interval);
}
and
var runwayIntval = cycle("div", "active", 100);
and at some point
clearInterval(runwayIntval);
See: http://jsfiddle.net/arNY8/1/
Of course you could argue that toggling a CSS class is a little limited. You could work with two callback functions instead: one to switch on a freely definable effect, one to switch it off:
function cycle(elems, enable, disable, interval) {
var prev = elems[0], index = 0;
if (elems.length === 0) return;
return setInterval(function () {
index %= elems.length;
if (prev) disable.call(prev);
enable.call(elems[index]);
prev = elems[index++];
}, interval);
}
and
var cycleIntval = cycle(
document.querySelectorAll("div"),
function () {
this.className += " active";
},
function () {
this.className = this.className.replace(/\s*\bactive\b/, "");
},
100
);

changing background image with a for loop

i have a table with 3 cells the middel 1 in a black image so it will look like there is a line in the middle of the screen.
now in the other cell i want to show pictures, so i tryed to do a loop that changing the images every second with by hiding the cells and then show them.
the script:
$(window).ready(function () {
//the images sits in a div with a hidden property.
var AlumniumPictures = $("#AlumnimPictureHolder").children();
var ShipozimPictures = $("#ShipozimPictureHolder").children();
//var timer = $.timer(yourfunction, 10000);
for (var i = 0; i < 10; i++) {
$(".almoniyomButtonTD").css({
"background-image": "url(" + $(AlumniumPictures[i]).attr('src') + ")"
});
$(".shipozimButtonTD").css({
"background-image": "url(" + $(ShipozimPictures[i]).attr('src') + ")"
});
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
//for some reson the code dosnt work if im not using the setInterval method.
document.setInterval(1000);
}
});
this is not working it only show me the first images and then stop.
is there a batter way to do this?
am im doing this right?
I think you might do this for the background:
$(window).ready(function () {
//the images sits in a div with a hidden property.
var AlumniumPictures = $("#AlumnimPictureHolder").children();
var ShipozimPictures = $("#ShipozimPictureHolder").children();
//var timer = $.timer(yourfunction, 10000);
time = 0;
step = 1000; // One secund
for (var i = 0; i < 10; i++) {
time+= step;
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
//for some reson the code dosnt work if im not using the setInterval method.
document.setInterval("changeBG('" + $(AlumniumPictures[i]).attr('src') + "', '.almoniyomButtonTD')", time);
document.setInterval("changeBG('" + $(AlumniumPictures[i]).attr('src') + "', '.shipozimButtonTD')", time);
}
});
function changeBG(image, obj) {
$(obj).css({
"background-image": "url(" + image + ")"
});
}
But I don't undestand what you want to do with this:
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
See the docs about setInterval. You need to tell it what code you are running.
window.setInterval(code, delay);
You aren't specifying any code for it to run! Try placing your for statement in a function and calling that.
Also, from Mozilla and MS docs setInterval seems to be on the window object, not on the document object. I don't think it will work the way you have it. I imagine if you looked in a debugger you would see an error thrown.
window.setInterval(myFunction, 1000);
function myFunction() {
for (var i = 0; i < 10; i++) {
$(".almoniyomButtonTD").css({
"background-image": "url(" + $(AlumniumPictures[i]).attr('src') + ")"
});
$(".shipozimButtonTD").css({
"background-image": "url(" + $(ShipozimPictures[i]).attr('src') + ")"
});
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
}
}

Redirecting in 10,..9,... script

Hy,
I have a 10 sec. delay page.
var t = window.setTimeout('redirect(strUrl)', 11000);
And function redirect(strUrl) just does document.location
What would be nice if i have a little message displaying at the bottom of my page, for example: Redirecting in 10 seconds...
"one second later that setTimeout fired"
...Redirecting to destiny in 9 seconds..
etc
ps. and the dots at the end going from left to right you know it. .. ...
I myselft would probably find out how to get that every second of timeout and just with jquery altered the number ...if that would be possible at all.
var timeout = 11; // in seconds
var msgContainer = $('<div />').appendTo('body'),
msg = $('<span />').appendTo(msgContainer),
dots = $('<span />').appendTo(msgContainer);
var timeoutInterval = setInterval(function() {
timeout--;
msg.html('Redirecting in ' + timeout + ' seconds');
if (timeout == 0) {
clearInterval(timeoutInterval);
redirect(strUrl);
}
}, 1000);
setInterval(function() {
if (dots.html().length == 3) {
dots.html('');
}
dots.html(function(i, oldHtml) { return oldHtml += '.' });
}, 500);
See it on jsFiddle.
If you wanted to have the second(s) thing, replace the appropriate line above with...
msg.html('Redirecting in ' + timeout + ' second' + ((timeout != 1) ? 's' : ''));
Of course, this works well with English, but probably isn't as easy with other languages.
You can do that by creating a div you position absolutely with bottom and left coordinates, and update the text in the div by looping on each second. Something like this:
function redirect(strurl) {
var seconds = 10;
var div = $("<div/>").css({
position: "absolute",
left: "0px",
bottom: "0px"
}).appendTo(document.body);
continueCountdown();
function continueCountdown() {
--seconds;
if (seconds >= 0 ) {
div.text("...Redirecting in " + seconds + " seconds...");
setTimeout(continueCountdown, 1000);
}
else {
// Redirect here
document.location = strurl;
}
}
}
Live example
Note that that will be imprecise, because the timeout will not necessarily fire in exactly one second. But it'll be close.
try this:
var count=10;
window.setTimeout(function(){redirect(url)}, 1000);
function redirect(url){
if(--count==0){
location.href=url;
return;
}
$("#DIV_TO_DISPLAY_MESSAGE").text("redirecting in " + count+" secs.");
window.setTimeout(function(){redirect(url)}, 1000);
}
Define a variable with number of secs, and in setTimeout( ... , 1000 ) call function whitch will decrease number of secs, change content of some-div/span..., and if secs = 0 redirect .
i would go for countdown-plugin. there's an example available

Categories