Undifined error after switching through images in Javascript - javascript

I am trying to create a website with one picture in the middle that changes after a given time. However after running through the loop once, no picture is shown for a short while and my console shows:
Shortly after, it switches through the images again. But having the image dissapear for a short while is a no go.
My Javascript looks like this:
var allPictures = new Array();
var index = 0;
allPictures[0] = "imgA.jpg";
allPictures[1] = "imgB.jpg";
allPictures[2] = "imgC.jpg";
addEventListener("load",() => {
setInterval( function() {
changeImage()
}, 500);
});
function changeImage() {
document.getElementById("galleryPicture").src = allPictures[index];
if (index < allPictures.length) {
index += 1;
} else if (index >= allPictures.length) {
index = 0;
}
}
My HTML looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="main.css">
<title>Website</title>
</head>
<body>
<script src="pictureSwapScript.js"></script>
<div class="galleryPicture">
<img id= "galleryPicture" src="imgA.jpg">
</div>
</body>
</html>

The problem is the condition used to increment index, it will get outside the boundaries of the array.
Replace it with
if (index >= allPictures.length - 1) {
index = 0;
} else {
index += 1;
}
There are other minute improvements that can benefit your code, among which the most obvious to me is replacing:
setInterval( function() {
changeImage()
}, 500);
with just
setInterval(changeImage, 500);

Below code solves your usecase.
function changeImage() {
if (index < allPictures.length - 1) {
index += 1;
} else if (index >= allPictures.length - 1) {
index = 0;
}
document.getElementById("galleryPicture").src = allPictures[index];
}
You were trying to compare index value with length, index always starts from 0. Hence you will have to decrease length by 1 because length starts from 1

Related

How do I print each character of a string but with 1s of delay in JavaScript?

I want to print "Hello World" on the screen but its each character one by one with 1 second delay. I've used setInterval() function but its not working. Why?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<script>
function type(){
var text = "Hello World!";
var i;
var o = "";
for(i = 0;i < text.length;i++){
o += text[i]
document.write(o[i])
}
}
var exe = setInterval(type(), 1000);
</script>
</body>
</html>
There're so many mistakes in your code, I don't know where to start...
Sorry to put it this way, but here's a cleaner version follows your approach, mind the comments:
const text = "Hello World!";
// the timer reference
let timer;
// the current index
let i = 0;
// you don't need a for loop in setInterval, the function itself is aleady called in iterations, just treat it as a loop iteration.
function type() {
// print the current charater with current index
document.write(text[i]);
// increase the index
i++;
// if the index reaches the maximum text length, cease the timer
if(i >= text.length)
clearInterval(timer);
}
// pass in function, instead of calling it
timer = setInterval(type, 1000);
We simply split our string into arrays and, when inserted into the page, delete the first element.
When there are no elements left in our array, we stop the timer.
let str = 'Hello world'.split('');
const interval = setInterval(() => {
document.write(str[0]);
str = str.slice(1);
if (!str.length) {
clearInterval(interval);
}
}, 1000);
I've made few changes with your logic.
type() function will only do char print.
intialize starting position with 0 and text.
when i is same as text.length clearInterval
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<script>
var text = "Hello World!";
var i = 0;
var o = "";
function type() {
o += text[i];
document.write(o[i]);
i++;
if (i == text.length) {
clearInterval(interval);
}
}
var interval = window.setInterval(type, 1000);
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<script>
function type(){
var text = "Hello World!";
var o = "";
for(let i = 0;i < text.length;i++){
o += text[i];
setTimeout(()=> document.write(o[i]), i*1000);
}
}
type();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<script>
var i = 0
var o = "";
var text = "Hello World!";
function type(){
if(i < text.length){
o += text[i]
document.write(o[i])
i++
setTimeout(type, 1000)
}
}
setTimeout(type, 1000)
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
</body>
<script>
var i=0;
var text = "Hello World!";
var exe = setInterval(function (){if (i<text.length)
document.write(text[i])
i++;}, 1000);
</script>
</html>
Something like this perhaps?
const word = "Hello World";
function printWord(str) {
if (typeof str === "string") {
let curIndex = 0;
const interval = setInterval(() => {
if (curIndex < str.length) {
console.log(str[curIndex]);
curIndex++;
} else {
clearInterval(interval);
}
}, 1000);
}
}
printWord(word);
var interval = null
function type(){
var text = "Hello World!";
var i = 0;
interval = setInterval( () => {
if( i === text.length -1) {
clearInterval(interval);
}
document.write(text[i]);
console.log(text[i++]);
}, 1000)
}
type()
We can use the concept of a closure and maintain the index of the character to be printed as a closure variable.
Each time the interval callback function is executed, the index is incremented and the inner function takes the current value of the index from the lexical scope.
Then once the length of the text is equal to the index, the interval is cleared:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test</title>
</head>
<body>
<script>
function type(text, idx) {
document.write(text[idx]);
}
function start() {
//The index to keep track of and increment from the timer
let idx = 0;
//The text to iterate
const text = "Hello World!";
//Set up the interval with a callback and form a closure
const id = setInterval(() => {
//Refers to the text and idx from the lexical scope
type(text, idx++);
//Once the index has reached the length of the text
if (idx === text.length) {
//clear the interval id
clearInterval(id);
}
}, 1000);
}
//Invoke the main function
start();
</script>
</body>
</html>

My automatic image slider only shows the first two images

My automatic image slider only shows the first two images of the images array while tere are three images. I can't figure out why it is not working properly, I hope someone might know what is going wrong.
var images = [];
var i = 0;
//image array
images[0] = 'https://placeimg.com/900/600/animals?t=1515065784396';
images[1] = 'https://placeimg.com/900/600/animals?t=1515065867693';
images[2] = 'https://placeimg.com/900/600/animals?t=1515065784396';
function changeImage() {
"use strict";
document.getElementById("slider").src = images[i];
if (i < images.length - 1) {
i += 1;
} else {
i = 0;
}
setInterval(changeImage, 2000);
}
window.onload = changeImage;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Automatic Image Slider </title>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<img id="slider">
</body>
</html>
Here it is! I've modified your code so that it now will work, pay attention not to reinitialize the interval at every changeImage() call ;)
//image array
var images = [];
images[0] = 'https://placeimg.com/900/600/animals?t=1515065784396';
images[1] = 'https://placeimg.com/900/600/animals?t=1515065867693';
images[2] = 'https://placeimg.com/900/600/animals?t=1515065784397';
var i = -1;
function changeImage() {
"use strict";
++i;
if (i >= images.length) {
i = 0;
}
document.getElementById("slider").src = images[i];
}
setInterval(changeImage, 2000);
window.onload = changeImage;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> Automatic Image Slider </title>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<img id="slider">
</body>
</html>
images.length = 3
but
images.length - 1 = 2
so
(i < images.length - 1)
this condition work inly for i = 0 and i = 1
use this condition instead
(i < images.length)
Actually, your code works with a little bug. Note that your first and last image is the same.
And the huge bug of your code is that you are creating a new interval at each changeImage call, so the last image is being placed but fastly replaced for the first image.
Remove the setInterval(changeImage, 2000) from the changeImage function and call it like this:
window.onload = function() {
changeImage();
setInterval(changeImage, 2000)
}
Because your condition if (i < images.length - 1) is true only for 0 an 1
If you do if (i<=images.length-1) you will get all the three images

document.getElementById returns null for unknown reason

The code is for a slider to switch images. When I run the page I get this error:
Cannot set property 'onclick' of null.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Image Slider</title>
<link rel="stylesheet" type="text/css" href="sliderswag.css">
<script language="javascript" type="text/javascript" src="imgslidescript.js"></script>
</head>
<body>
<div id="box">
<img id="main" src="http://lmetar.com/oscar1.jpg">
<img id="left" src="http://lmetar.com/left.png">
<img id="right" src="http://lmetar.com/right.png">
</div>
JavaScript:
document.getElementById('left').onclick = slideChange;
document.getElementById('right').onclick = slideChange;
var slideNumber = 0;
function slideChange()
{
slideNumber += 1;
if (slideNumber > 3)
{
slideNumber = 1;
}
else
{
document.getElementById('main').src = 'http://lmetar.com/oscar' + slideNumber + '.jpg';
}
}
Move your script to the end of your page. You're running JavaScript on elements that don't yet exist.
Or wrap the code you have in a window.onload call which will execute the code after the window has loaded. Ex:
window.onload = function () {
document.getElementById('left').onclick = slideChange;
document.getElementById('right').onclick = slideChange;
var slideNumber = 0;
function slideChange() {
slideNumber += 1;
if (slideNumber > 3) {
slideNumber = 1;
} else {
document.getElementById('main').src = 'http://lmetar.com/oscar' + slideNumber + '.jpg';
}
}
};
Your JavaScript is loading before you content, therefore it is trying to find elements that do not exists. You have 2 options:
Move your <script> tag to the end of your page
Use the following to wait until the page has loaded before you execute your script
Code:
document.addEventListener("DOMContentLoaded", function(event) {
// Your Code Here
});

Javascript simple image slider

I would like to have a simple picture slider. That slider should be in the header of the website and should switch between a small delay. I want it simple and named the pictures 1.jpg, 2.jpg and so on and they are in the folder "bilder".
I have tried a bit and here is my result:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script type="text/javascript">
function picture_slider(){
setInterval( switch_picture(), 3000 );
return false;
}
function switch_picture() {
for ( var i = 1; i < 7 ; i++ ) {
var pfad = "bilder/" + i + ".jpg";
document.getElementById("bild").src = pfad;
i++;
};
return false;
}
</script>
</head>
<body onload="picture_slider();">
<img id="bild" src="" />
</body>
</html>
I guess, that I did something wrong, because my browser is showing only one picture and is not switching.
jsBin demo
On every loop you're iterating (for loop) over all your images, resulting in the latest one. Also use only switch_picture (instead of switch_picture()).
P.S: create an 0.jpg image for this counter:
function picture_slider(){
setInterval( switch_picture, 2000 ); // corrected removing "()"
}
var bild = document.getElementById("bild")
var i = 0; // Start from image 0.jpg
function switch_picture() { // don't iterate a loop in here!
bild.src = "bilder/"+ (i++ % 7) +".jpg";
}
I found something here: Stackoverflow Link
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script type="text/javascript">
var i = 0;
var images = [ "1", "2", "3", "4", "5", "6", "7"]
function picture_slider(){
setInterval( switch_picture, 2000 );
}
function switch_picture() {
i++;
if ( i >= images.length ) {
i = 0;
};
var bild = document.getElementById("bild");
bild.src = "bilder/" + images[i] + ".jpg";
}
</script>
</head>
<body onload="picture_slider();">
<img id="bild" src="" />
</body>
</html>
// 1. images need to store in an Array
const images = [
"img/pic-1.jpg",
"img/pic-2.jpg",
"img/pic-3.jpg",
"img/pic-4.jpg",
"img/pic-5.jpg",
"img/pic-6.jpg",
"img/pic-7.jpg"
];
// 7. getElementById by calling, store globally (do not call inside loop/setInterval performance will loose)
const imgElement= document.getElementById("slider-image");
// 2. set initial value for array index
let imgIndex = 0;
// 3. create setInterval()
const sliderInterval = setInterval(() => {
// 6. check condition if length is finished then start again from 0
if (imgIndex >= images.length) { // use >= because index start from 0 and length start from 1, if use just > then last element will be undefined
imgIndex = 0;
}
// 5. testing
// console.log(imgIndex);
// 9. Dynamically change image src
const imgUrl = images[imgIndex];
imgElement.setAttribute('src', imgUrl);
// 4. increase value by 1
imgIndex++;
}, 1000);

JavaScript undefined variable in an anonymous function

This code is supposed to switch the display property of all children elements of #slide-container to "block" with time delay two seconds between the switches.
var magic = window.setInterval(function(){
if (document.readyState === "complete") {
var children = document.getElementById('slide-container').children;
for (var i = 0; children.length > i; i++ ) {
setTimeout(function(){
children[i].style.display = "block";
console.log(i);
},2000);
}
magic = window.clearInterval(magic);
} else {
console.log("...");
}
}, 1000);
I am using it along with this html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>
<ul id="slide-container">
<li style="display: none;"><img src="http://i.imgur.com/8qBcyzc.jpg"></li>
<li style="display: none;"><img src="http://i.imgur.com/oxMTFTF.png"></li>
<li style="display: none;"><img src="http://i.imgur.com/JTM6Yqg.jpg"></li>
</ul>
</body>
</html>
I get error Uncaught TypeError: Cannot read property 'style' of undefined
It says it cannot find children or children[0]. But that variable has been specified and the dom nodes exist.
Closure issue.
Try adding a 3rd parameter to the setTimeout (doesn't work):
setTimeout(function(i){
children[i].style.display = "block";
console.log(i);
}, 2000, i);
Example
Another formate:
var i = 0;
var timer = setInterval(function () {
children[i].style.display = "block";
i++;
if (i == children.length) {
clearInterval(timer);
}
}, 2000);
EXAMPLE
ES6 is around the corner, the let statement is especially built for situations like this:
for (let i = 0; children.length > i; i++ ) {
setTimeout(function(){
children[i].style.display = "block";
console.log(i);
}, 2000);
}
However this is not the answer you need for right now. This was just a note.
Try encasing the setTimeout in an IIFE (Immediately invoked function expression)
for (var i = 0; children.length > i; i++) {
(function (index) {
setTimeout(function () {
children[index].style.display = "block";
console.log(i);
}, 2000);
})(i);
}
Check Fiddle
The reference of i is common to all the functions executed by setTimeout . So by the time the function inside executes , the value of i will point to children.length .
But there is no element that refers to children[children.length] which does not exist and throws an error.
By the time setTimeout is ready i will be the length of children so you have to capture the value of i
try this
var time = 2000;
for (var i = 0; children.length > i; i++ ) {
(function( child, time) {
window.setTimeout(function() {
child.style.display = "block";
}, time);
}( children[i], time));
time += 2000;
}
or you could do this. ... I have fixed the delay thing
var hideElement = function( element, time) {
window.setTimeout(function() {
element.style.display = 'block';
}, time);
};
var time = 2000;
for (var i = 0; children.length > i; i++ ) {
hideElement(children[i], time);
time += 2000;
}

Categories

Resources