Cannot read property 'style' of undefined at slideshow ERROR - javascript

I am new to javascript and I am trying to create a slideshow inside divs. However when I do it give me the error message
Uncaught TypeError: Cannot read property 'style' of undefined
at slideshow (script.js:14)
at script.js:1
This is my HTML code:
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<script type="text/javascript" src="script.js"></script>
<div id="wrapper">
<div id="content">
<div id="top">
<img class="slide" src="1.png" style="width:100%">
<img class="slide" src="2.png" style="width:100%">
</div>
<div id="left">
</div>
<div id="middle">
</div>
<div id="right">
</div>
</div>
</div>
</body>
</html>
This is my CSS code:
.slide {
display:none;
}
This is my Javascript code:
slideshow();
function slideshow() {
var index = 0;
var i;
var slides = document.getElementsByClassName("slide");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
index++;
if (index > slides.length) {
index = 1;
}
slides[index-1].style.display = "block";
setTimeout(slideshow, 2000);
}
I think the problem is that the javascript cannot access the images when they are in the div.

1. You are placing the <script> file before the slides. So when your script is executed the first time, the markup does not yet exist in DOM.
Because your slides do not exist, after the initial for (which does nothing), you get to this line
slides[index-1].style.display = "block";
But slides[0] does not exist, so it doesn't have a .style property.
2. You are reassigning the value of 0 to index each time you re-run the function, so it will always show the same slide: the first.
(3.) You chose display as the method to show/hide your slides, which is not animatable. Therefore, your slides will change abruptly, there's no possibility of transition.
(4.) In addition, just as a matter of personal choice, I prefer document.querySelectorAll('.slide') to document.getElementsByClassName("slide"). I don't know exactly why. Probably because it's shorter and maybe because it allows a more flexible selector syntax (classes, ids. attributes or any other valid css selector).

Related

why is event.button not working properly with mousedown event in Chrome?

Here's a picture of the error:
I'm trying to get the event.button to do something when someone left clicks on a image, but the event.button is not working for me. I don't know why I'm getting this error. Is it saying that my event parameter is undefined in my Javascript code, or is it saying that buttons is undefined? I don't understand, I could use some help with this question. I set event.buttons equal to x and if x == 1 which means if someone left clicks one of images then something happens.
Here is the javascript code:
function dontShowDots(event) {
var x = event.buttons;
if (x == 1) {
arrayDots[0].style.display = "none";
arrayDots[1].style.display = "none";
}
}
Here's my html code:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="container">
<div class="empty-squares"><img src="images/greenDot.png" height="50px" width="60px"></div>
<div class="empty-squares"><img src="images/greenDot.png" height="50px" width="60px"></div>
<div id="square1"><img src="images/white_pawn.png" onclick="showDots()" height="75px" width="75px"></div>
</div>
<div id="container1">
<div class="empty-squares"><img src="images/greenDot.png" height="50px" width="50px"></div>
<div class="empty-squares"><img src="images/greenDot.png" height="50px" width="50px"></div>
<div id="square2"><img src="images/white_pawn.png" onmousedown="dontShowDots()" onclick="showDots2()" height="75px" width="75px"></div>
</div>
<script src="interactive.js"></script>
</body>
</html>
css code:
.empty-squares img {
display: none;
}
Try:
onmousedown="dontShowDots(event)"
onmousedown="dontShowDots(event)"
One can access the current event through window.event. Just using event is implicitly accessing window.event.

How do I loop through HTML elements while executing a function on each element

I am a newbie to Javascript, I wanted to implement a for loop that would go through each div as selected by its class.
The simple idea is to reveal DIVs when I click on a button. But it has to be sequential: I click DIV1 appears, when I click again DIV2 appears and so on. Currently my code only changes the class of one DIV and not the rest. Here are my code samples:
$(document).ready(function(){
// jQuery methods go here...
var count = document.getElementById("page1").childElementCount;
for(var i = 0; i < count; i++){
var myClass = ".panel" + i;
$("button").click(function(){
$(myClass).addClass("showing animated fadeIn")
});
}
});/**document ready **/
.showing{
background-color: red;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
<link rel="stylesheet" type="text/css" href="mystyle.css">
<link rel="stylesheet" type="text/css" href="animate.css">
</head>
<body>
<button class="one">Click Me!</button>
<div id="page1">
<div class="panel1">
</div>
<div class="panel2">
</div>
<div class="panel3">
</div>
<div class="panel4">
</div>
</div><!-- page one -->
<div id="trial">
</div>
<script src="jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="jquery.touchSwipe.min.js"></script>
<script type="text/javascript" src="trial.js"></script>
</body>
</html>
Please let me know what I am missing especially in the for loop or if I can do something else to be able to grab a DIV and add a class every time I click on the button.
Firstly, the HTML attribute class is made for multiple elements with the same style/behaviour. You should use id if it is to dissociate one panel for another.
You have to store a count variable to know which panel has to appear next.
And always try to do what you want in Javascript without jQuery if it is possible !
var i = 1;
function clickBtn() {
if (!document.getElementById("panel-" + i))
return;
document.getElementById("panel-" + i).classList.add("visible");
i++;
}
.panel {
width: 50px;
height: 50px;
display: none;
margin: 5px;
background-color: #bbb;
}
.panel.visible {
display: block;
}
<button onclick="clickBtn()">click me</button>
<div>
<div id="panel-1" class="panel"></div>
<div id="panel-2" class="panel"></div>
<div id="panel-3" class="panel"></div>
<div id="panel-4" class="panel"></div>
</div>
You could use counter like clickCount instead of for loop
$(document).ready(function(){
// jQuery methods go here...
var clickCount = 1;
$("button").click(function(){
var myClass = ".panel" + clickCount;
$(myClass).addClass("showing animated fadeIn")
clickCount++;
});
});/**document ready **/
.showing{
background-color: red;
height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
<link rel="stylesheet" type="text/css" href="mystyle.css">
<link rel="stylesheet" type="text/css" href="animate.css">
</head>
<body>
<button class="one">Click Me!</button>
<div id="page1">
<div class="panel1">
</div>
<div class="panel2">
</div>
<div class="panel3">
</div>
<div class="panel4">
</div>
</div><!-- page one -->
<div id="trial">
</div>
<script src="jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="jquery.touchSwipe.min.js"></script>
<script type="text/javascript" src="trial.js"></script>
</body>
</html>
You've got this a little bit backwards; you're trying to attach an event handler to the button for each element. Instead, you should have one event handler for the button, which cycles through the elements.
You could set a variable to keep track of which element is currently highlit, but it's easier to just determine that based on the current state of the DOM:
$(document).ready(function() {
$('button.one').click(function() {
$('.showing') // find the current element
.removeClass('showing') // clear it
.next() // find its next sibling
.addClass('showing'); // show that
if ($('.showing').length === 0) {
// nothing is showing, so show the first one
$('#page1 div:eq(0)').addClass('showing')
}
})
})
#page1 div {height: 10px}
#page1 div.showing {background-color: red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="one">Click Me!</button>
<div id="page1">
<div class="panel1"></div>
<div class="panel2"></div>
<div class="panel3"></div>
<div class="panel4"> </div>
</div>
There's a small cheat in the above -- if the current element is the last one, then it won't have a next() to highlight. That's why I waited to check for the case where there's nothing visible until after moving the highlight; that way it will work for both the first click, and for when you need the highlight to loop back around to the first element.
If you intended to have the elements reveal themselves in sequence and not hide earlier ones, just get rid of the .removeClass('showing') line:
$(document).ready(function() {
$('button.one').click(function() {
$('.showing') // find the current element
.next() // find its next sibling
.addClass('showing'); // show that
if ($('.showing').length === 0) {
// nothing is showing, so show the first one
$('#page1 div:eq(0)').addClass('showing')
}
})
})
#page1 div {height: 10px}
#page1 div.showing {background-color: red}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="one">Click Me!</button>
<div id="page1">
<div class="panel1"></div>
<div class="panel2"></div>
<div class="panel3"></div>
<div class="panel4"> </div>
</div>
What you can do is count the amount of children that you have, and compare the amount of clicks through a given iterator you have to see what should be shown.
I added an extra functionality that hides the elements again once the max amount of divs has been shown.
Hope this helps.
$(document).ready(function() {
$('#page1').children().each(function () {
$(this).hide();
});
});
var panel="panel";
var pannelNum=0;
var count = $("#page1").children().length;
$(".one").on( "click", function() {
pannelNum=pannelNum+1;
if(pannelNum > count) {
$('#page1').children().each(function () {
$(this).hide();
});
pannelNum=0;
}
else {
clicked=panel+""+pannelNum;
$('.'+clicked).show();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="one">Click Me!</button>
<div id="page1">
<div class="panel1">
this is panel 1!
</div>
<div class="panel2">
this is panel 2!
</div>
<div class="panel3">
this is panel 3!
</div>
<div class="panel4">
this is panel 4!
</div>
</div><!-- page one -->
<div id="trial">
</div>

Slideshows in HTML/Javascript

I have tried making a slideshow in js and its not working, all I get is the images displayed on the screen in order and the next and previous links just send me to the top of the page. I can't work out why, i know solutions that do work but I don't understand why this solution is not working. There are many solutions I have found online that are very similar to this one and they work, yet this one doesn't, I have only recently started js so I imagine its something silly I have missed. Here is the HTML: (edit: moved the to the bottom of the html body)
<html>
<head>
<title></title>
<link type="text/css" rel="stylesheet" href="CSS/mainPageStyle.css">
</head>
<body style="background-color:white">
<div id="titleLogo"><h1>Custom Motorbikes</h1></div>
<nav>
<ul>
<li>Home</li>
<li>About Us</li>
<li>Full ride list</li>
<li>Custom ride</li>
<li>Contact Us</li>
<li>Login</li>
<li>Register</li>
</ul>
</nav>
<!-- front page slideshow: -->
<img src="images/bikePerson.jpg" class="slides" style="width:100%" />
<img src="images/bikePersonCountry.jpg" class="slides" style="width:100%" />
<img src="images/bikeRoad.jpg" class="slides" style="width:100%" />
Next Slide <br/>
Previous Slide
<!-- front page slideshow -->
<script type="text/javascript" src='JS/slideshow.js'></script>
</body>
</html>
here is the js:
var imgPos = 0;
var changeImage(0); //called so that images(except first one) are hidden intially
var imgs = document.getElementsByClassName("slides"); //creates an array, and fills it with all images with 'slides' class
var arrayLength = imgs.length;
function changeImage(x) {
var i = 0; //used for counting through 'for' loop
imgPos += x; //x will be either -1 or +1
if (imgPos > arrayLength){ //if user goes beyond last img
imgPos = 0; //go to first img
}
if (imgPos < 0){ //if user goes before first img
imgPos = arrayLength; //go to furthest img
}
for (i = 0; i < arrayLength; i++){
imgs[i].style.display = "none"; //this hides all the images
}
imgs[imgPos].style.display = "block"; //this then displays the image we want to see
return false;
}
Here are the errors:
Uncaught TypeError: Cannot read property '0' of undefined(…) slideshow.js:22
Uncaught TypeError: Cannot read property '1' of undefined(…)
Method 1 (Move the js to the bottom)
This will run after all of you dom has loaded.
<html>
<head>
<title></title>
<link type="text/css" rel="stylesheet" href="CSS/mainPageStyle.css">
</head>
<body style="background-color:white">
<div id="titleLogo"><h1>Custom Motorbikes</h1></div>
<nav>
<ul>
<li>Home</li>
<li>About Us</li>
<li>Full ride list</li>
<li>Custom ride</li>
<li>Contact Us</li>
<li>Login</li>
<li>Register</li>
</ul>
</nav>
<!-- front page slideshow: -->
<img src="images/bikePerson.jpg" class="slides" style="width:100%" />
<img src="images/bikePersonCountry.jpg" class="slides" style="width:100%" />
<img src="images/bikeRoad.jpg" class="slides" style="width:100%" />
Next Slide <br/>
Previous Slide
<!-- front page slideshow -->
<script type="text/javascript" src='JS/slideshow.js'></script>
</body>
</html>
Method 2 (add document ready)
This will trigger the dom loaded event after your dom is loaded.
Note: You can not assign a function to a var var changeImage(0); You can assign the result of a function to a variable though: var myVar = changeImage(0);
var imgPos = 0;
var imgs = [];
function changeImage(x) {
var i = 0; //used for counting through 'for' loop
imgPos += x; //x will be either -1 or +1
imgPos = imgPos + 1 > imgs.length ? 0 : imgPos;
imgPos = imgPos < 0 ? imgs.length - 1 : imgPos;
for (let i = 0; i < imgs.length; i++) {
imgs[i].style.display = "none"; //this hides all the images
}
imgs[imgPos].style.display = "block"; //this then displays the image we want to see
console.log(imgs[imgPos])
return false;
}
document.addEventListener('DOMContentLoaded', event => {
imgs = document.querySelectorAll("img.slides"); //creates an array, and fills it with all images with 'slides' class
changeImage(0); //called so that images(except first one) are hidden intially
});

Controlling multiple CSS events with single Function

I am struggling to change CSS based on user actions with some script. Currently I have each navBar button performing 5 functions onClick. 1 each to change the CSS of 5 different divs. Since I am newer to scripting, I wanted to make an example similar to what I am doing in order to refer back in the future as well as hopefully help out the next person to come along.
Can someone please help me with this short example? I have tried many various scripts and just end up destroying my spirits.
For this, I want to click an openButton in the navBar and have it change the width (essentially open) a corresponding div on the page.
<div id="navBar">
<a id="div1OpenButton" class="openButton" onClick="openDiv()">div1</a>
<a id="div2OpenButton" class="openButton" onClick="openDiv()">div2</a>
<a id="div3OpenButton" class="openButton" onClick="openDiv()">div3</a>
</div>
<div id="main">
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
</div>
<style>
#div1 {width: 0px;}
#div2 {width: 0px;}
#div3 {width: 0px;}
</style>
Don's use onclick within your HTML - that is bad practice. You want a separation of concerns, with your JS in a separate file.
If you use jQuery (which a good library for a use-case like this), you can use its powerful selector to select all five elements at the same time. jQuery's selector is nice for beginners because it's identical to how you use selectors in CSS.
I also like to attach my JS to my HTML via IDs, not classes. This way, you know your JS has unique HTML targets to attach to.
Putting all of this together, use the jQuery selector to select all buttons, then use a .click() event to encapsulate your CSS manipulation in an anonymous function:
$(".openButton").click(function() {
$("#div1, #div2, #div3").css("width", "500px");
});
There are better ways to do it, but following the line of your code, you must pass a param to your openDiv function such as the ID of the element you want to show.
<a id="div1OpenButton" class="openButton" onClick="openDiv('div1')">div1</a>
Your onClick function must to hide all divs inside your "main" and show only the id you just passed by param.
If you need more help, paste your code please.
Try this
<html><head>
<script src=path/to/jquery.js></script>
</head><body>
<div id="navBar">
<!-- openDiv(1) with "1" is the div number -->
<a id="div1OpenButton" class="openButton" onClick="openDiv(1)">div1</a>
<a id="div2OpenButton" class="openButton" onClick="openDiv(2)">div2</a>
<a id="div3OpenButton" class="openButton" onClick="openDiv(3)">div3</a>
</div>
<div id="main">
<div id="div1">div1 opened</div>
<div id="div2">div2 opened</div>
<div id="div3">div3 opened</div>
</div>
<style>
div#main div {overflow:hidden;width:0px} //to hide div content while closed
</style>
<script>
function openDiv(n) {
$('#div'+n).width(400);} // set width to 400px
</script>
</body></html>
OR without the inline onClick()
<html><head>
<script src=path/to/jquery.js></script>
</head><body>
<div id="navBar">
<a id="div1" class="openButton" >div1</a>
<a id="div2" class="openButton" >div2</a>
<a id="div3" class="openButton" >div3</a>
</div>
<div id="main">
<div id="div1">div1 opened</div>
<div id="div2">div2 opened</div>
<div id="div3">div3 opened</div>
</div>
<style>
div#main div {overflow:hidden;width:0px} //to hide div content while closed
</style>
<script>
$('a.openButton').click(function() {
var itm = $(this).attr("id");
$("#main div#"+itm).width(400);} );// set width to 400px
</script>
</body></html>
Firstly, don't mix HTML, CSS and JavaScript in the same file. You should write your JavaScript code in a .js file, and your styles in an external stylesheet ;
Add handlers on events in your JavaScript code by using element.addEventListener() ;
Use data attributes on your buttons to link them with target divs.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>My page</title>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div id="navBar">
<a class="openButton" data-target="div1">div1</a>
<a class="openButton" data-target="div2">div2</a>
<a class="openButton" data-target="div3">div3</a>
</div>
<div id="main">
<div id="div1" class="container hide"></div>
<div id="div2" class="container hide"></div>
<div id="div3" class="container hide"></div>
</div>
</body>
</html>
And in the script.js file:
document.addEventListener('DOMContentLoaded', function(event) {
var divs = document.querySelectorAll('.openButton');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', openDiv);
}
});
function openDiv(e) {
// Use e.target.dataset.target
// Add 'hide' class on all containers
var containers = document.querySelectorAll('.container');
for (var i = 0; i < containers.length; i++) {
containers[i].classList.add('hide');
}
// Remove 'hide' class on the container to display
document.getElementById(e.target.dataset.target).classList.remove('hide');
}
<a id="div1OpenButton" class="openButton" onClick="openDiv(this)">div1</a>
<script>
function openDiv(e){
document.getElementById(e.innerHTML).style.width= '20px'
}
</script>

pass CSS .class as a parameter to javascript function

the goal here is onclick of 1.gif, everything with .panel1 class disappears(style.display.none), and everything with a .panel2 class becomes visable (style.display.inline)
I'm new at this..so I think its just a syntax issue with ' ' or maybe " "
<!DOCTYPE html>
<html>
<head>
<title>main</title>
<meta charset="utf-8">
<style type="text/css">
.panel1 {display:inline;}
.panel2 {display:none;}
</style>
<script type="text/javascript">
function panelTransition(panelOut,panelIn)
{
document.getElementByClass(panelIn).style.display="inline";
document.getElementByClass(panelOut).style.display="none";
}
</script>
</head>
<body>
<img class="panel1" src=1.gif onclick="panelTransition(panel1,panel2)" />
<img class="panel2" src=2.gif />
</body>
</html>
There is no getElementByClass. It's getElementsByClassName, and it returns an array of items, so you'll need to modify your code to loop through them.
function panelTransition(panelOut, panelIn) {
var inPanels = document.getElementsByClassName(panelIn);
for (var i = 0; i < inPanels.length; i++) {
inPanels[i].style.display = 'inline';
}
var outPanels = document.getElementsByClassName(panelOut);
for (var i = 0; i < outPanels.length; i++) {
outPanels[i].style.display = 'none';
}
}
If you were using a JavaScript library, like jQuery, this would be much easier to do. Also, as has been mentioned, you need quotes around your arguments to panelTransition.
<img class="panel1" src=1.gif onclick="panelTransition('panel1', 'panel2')" />
<img class="panel2" src=2.gif />
<img class="panel1" src=1.gif onclick="panelTransition('panel1','panel2')" />
I think you need quotes there
<html>
<head>
<title>main</title>
<meta charset="utf-8">
<style type="text/css">
.panel1 {display:inline;}
.panel2 {display:none;}
</style>
<script type="text/javascript">
function panelTransition(panelOut,panelIn)
{
// panelIn gets turned on
setDisplay(panelIn,"inline");
// panelOut gets turned off
setDisplay(panelOut,"none");
}
function setDisplay(className,displayState)
{
// retrieve a list of all the matching elements
var list = document.getElementsByClassName(className);
// step through the list
for(i=0; i<list.length; i++) {
// for each element, set the display property
list[i].style.display = displayState;
}
}
</script>
</head>
<body>
<img class="panel1" src="1.gif" onclick="panelTransition('panel1','panel2')" />
<img class="panel2" src="2.gif" onclick="panelTransition('panel2','panel1')" />
</body>
</html>
Or you can accomplish the same in jQuery
// fires when the page is up and running
$(document).ready(function(){
// find all the panel1 elements,
// attach an on click handler
$(".panel1").bind("click", function(){
// find all the panel1 elements
// set their css display property to inline
$(".panel1").css("display","inline");
// find all the panel2 elements
// set their css display property to none
$(".panel2").css("display","none");
});
$(".panel2").bind("click", function(){
$(".panel2").css("display","inline");
$(".panel1").css("display","none");
});
});
You can learn all about jQuery here : http://www.jquery.com/
You'll only be able to get your code to run once, as soon as you click a panel1 image all of the panel2 images will disappear, you won't be able to click them back on ever again.

Categories

Resources