Im still new at javascript ive been learning the concepts for several months and this is my first time taking a crack at it.
Im trying to create a carousel using css3 and Javascript (no Jquery)
the console keeps throwing an error.
Uncaught TypeError: Cannot read property display of undefined
The following is my html and javascript code
var slideShow = document.querySelectorAll('.inside');
for (var i = 0; i < slideShow.length; i++) {
setTimeout(function() {
slideShow[i].display.style = 'inline-block';
}, 2000)
}
<div class="inside">
<div class="inner1">
<h1>This is Inner div 1</h1>
</div>
<div class="inner2">
<h1>This is Inner div2</h1>
</div>
<div class="inner3">
<h1>This is Inner div3</h1>
</div>
<div class="inner4">
<h1>This is Inner div4</h1>
</div>
</div>
Aside from display and style being in the wrong order, the problem is that by the time the setTimeout callback function is executed, the for loop has already ended, and i is equal to the length of the nodeList (and since the last element's index is one less than the length of the nodeList, an error is thrown).
You could capture the value of i in an IIFE:
Example Here
var slideShow = document.querySelectorAll('.inside');
for (var i = 0; i < slideShow.length; i++) {
(function (i) {
setTimeout(function () {
slideShow[i].style.display = 'inline-block';
}, 2000 * (i + 1));
})(i);
}
or you could use the .forEach() method:
Example Here
var slideShow = document.querySelectorAll('.inside');
Array.prototype.forEach.call(slideShow, function (el, i) {
setTimeout(function () {
el.style.display = 'inline-block';
}, 2000 * (i + 1));
});
Alternatively, you could just use setInterval:
Example Here
var slideShow = document.querySelectorAll('.inside');
var i = 0;
var interval = setInterval(function () {
if (i < slideShow.length) {
slideShow[i].style.display = 'inline-block';
i++;
} else {
clearInterval(interval);
}
}, 2000);
You have display and style in the wrong order.
It should be slideShow[i].style.display='inline-block';
Additionally, slideShow is only an array-like object of length 1: it contains the div .inner but not its children. If you want to iterate through the child elements, use
var slideShow = document.querySelector('.inside').children;
Edit: As Josh pointed out in a separate answer, you have another problem as well in using setTimeout within a for loop. By the time the function inside the timeout executes, i will be 4, which will give you an undefined value.
If you insist on using a for loop, you can also do this using the forEach method. However, slideShow is not technically an array, but rather an "array-like object", so it does not have its own forEach method. Instead, you must invoke the Array.prototype method as such:
[].forEach.call(slideShow, function(item) {
setTimeout(function() {
item.style.display = 'inline-block';
}, 2000);
});
problem is you are only selecting div.inside and it is not returning div.inner
Try this if you want to select all .inner
change class="inside" to id="inside" and copy this js
var slideShow=document.getElementById("inside").querySelectorAll('div');
slideShow[1].style.backgroundColor = "red";
for (var i=0; i<slideShow.length; i++){
setTimeout(myFun(i), 2000)
}
function myFun(i ){slideShow[i].style.display = "inline-block";}
Related
First post on here, so bear with me! I'm supposed to insert 100 h3 headings on page load ("Accusation 1, Accusation 2, Accusation 3,...Accusation 100"). We're only using 1 loop for the entire lab, and that will be used with other code in the lab, so I'm trying to do this without using a loop, if possible.
**Also, the lab is supposed to teach about scope and hoisting, so we can't use "let" or "const", only "var".
var accusation = 1;
var createHeading = function () {
var heading = $('<h3></h3>').text("Accusation " + accusation);
$('body').append(heading);
accusation++;
}
$(document).ready(function () {
createHeading();
accusation++;
console.log(accusation);
if (accusation > 100) {
return;
console.log('reached 100');
}
})
I'm wanting this function to repeat and increment without using a loop, but it's only producing the first h3 heading.
Recursion! Have the function call itself.
var accusation = 1;
var createHeading = function() {
var heading = $('<h3></h3>').text("Accusation " + accusation);
$('body').append(heading);
accusation++;
if (accusation >= 100) {
console.log("Reached 100;");
return;
} else {
createHeading();
}
}
$(document).ready(function() {
createHeading();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You could use Array.from() and it's internal mapper callback to build an elements array and simply append that array
var headings = Array.from({length:100}, (_,i) => $('<h3>', {text: `Accusation ${i+1}`}))
$('body').append(headings)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
There is a simple Slider Effect below, but I have some question with it:
it's work
$(function () {
var slideIndex = 1;
SliderShow(slideIndex);
function plusIndex(n) {
SliderShow(slideIndex += n);
}
function SliderShow(n) {
var Slider = $('.Slider');
var SliderItem = Slider.children('li');
if (n > SliderItem.length) {
slideIndex = 1;
}
if (n < 1) {
slideIndex = SliderItem.length;
}
for (var i = 0; i < SliderItem.length; i++) {
SliderItem[i].style.display = "none";
}
SliderItem[slideIndex - 1].style.display = "block";
}
$('.prevBtn').click(function () {
plusIndex(-1);
});
$('.nextBtn').click(function () {
plusIndex(+1);
});
});
but when I change SliderItem[i].style.display = "none" to SliderItem[i].hide() the slide was broken, what's wrong with it?
There is any different between Jquery hide and js style?
Did I misunderstand sometihing?
Because this SliderItem[slideIndex-1] returns a native DOM element which does not have a hide method, you need to wrap it with jQuery function $:
$(SliderItem[slideIndex-1]).hide();
To answer your first question "difference between jquery hide and js style"
The behaviour of these two are most likely the same except for one thing.
By using SliderItem[i].style.display = "none"
You are only changing the style display to none
While JQuery .hide() does an extra stuff which is saving the previous value of display property to cache so you can get back to it later when you use .show().
You may check this link as reference.
Here is the HTML:
<div class=column1of4>
<a rel="Appendix" href="images/watermarks/watermark_pic1.jpg"
title="Bottle in the mirror">
<img src="images/250-width/pic1.jpg"
alt="" width="250px" height="250px"
id="Bottleinthemirrorpic">
</a>
<a rel="Appendix" href="images/watermarks/watermark_pic1.jpg"
title="Bottle in the mirror">
<div id="Bottleinthemirror" class="spanlink">
<p>Bottle in the mirror</p>
</div>
</a>
</div>
and here is the Javascript:
var texts = ['#Bottleinthemirror'];
var picture = ['#Bottleinthemirrorpic'];
for ( var i = 0; i < 1; ++i ) {
$.each(texts, function(i) {
$(this).hide();
$([this, picture[i]]).hover(function() {
$(this).show();
}, function() {
$(this).hide();
});
});
Basically, when I hover over #Bottleinthemirrorpic, I want #Bottleinthemirror to show up and I want #Bottleinthemirror to go away when I hover off of both of them.
I want the for loop because I am going to add more elements to texts and picture, I'm just wondering why the Javascript doesn't work? It doesn't seem to hide #Bottleinthemirror.
This code works but I want to be able to loop through the elements inside texts and picture which is why I am not using this code:
$('#Bottleinthemirror').hide();
$('#Bottleinthemirrorpic, #Bottleinthemirror').hover(function() {
// in
$('#Bottleinthemirror').show();
}, function() {
// out
$('#Bottleinthemirror').hide();
});
Nested loops are unnecessary, where the arrays are one-dimensional. You can try something like:
var texts = ['#Bottleinthemirror'],
pictures = ['#Bottleinthemirrorpic'],
i, j, curText, curPicture, generateHandlers;
generateHandlers = function (text, picture) {
$(text).hide();
$(text + "," + picture).hover(function () {
//in
$(text).show();
},function () {
//out
$(text).hide();
});
};
for (i = 0, j = texts.length; i < j; i++) {
curText = texts[i];
curPicture = pictures[i];
generateHandlers(curText, curPicture);
}
DEMO: http://jsfiddle.net/hQ8xt/
The immediate problem with binding events in a loop is that the event is triggered later, when the loop has finished. So by that time, the iterator (in this case, i) has reached the last value (in this case, j). You need to create a new scope to capture the values in the arrays, which is what I've done by calling the generatedHandlers function and passing the array values.
One thing I'd suggest is to combine the texts and pictures arrays into an object, like:
var textPics = {
'#Bottleinthemirror': '#Bottleinthemirrorpic'
};
And loop over that like:
var curText, curPicture;
for (curText in textPics) {
curPicture = textPics[curText];
generateHandlers(curText, curPicture);
}
I have this code here:
function slideDown(){
//get the element to slide
var sliding = document.getElementById('slideDiv'+x);
//add 1px to the height each time
sliding.style.height = parseInt(sliding.style.height)+5+'px';
t=setTimeout(slideDown,15);
if (sliding.style.height == "401px"){clearTimeout(t);}
}
which gets element slideDivx and increases its height until it reaches 401px.
I have 20 of these divs (each called slideDiv1, slideDiv2, ...) and what I want is for div 10 to start, then when it has reached about 100px in height, I want 9 and 11 to start and so on so forth.
I've tried setInterval and increased x each time, but that doesn't work because it stops the previous div animating and moves on to the next one before it's finished. I think that's because I'm changing that function right?
What I'm wondering is, do I have to duplicate the function for each set of divs or can I automate that?
I have to be able to do it all in native JavaScript rather than jQuery because it's for a university project.
It sounds like you simply need to create slideDown with a parameter and then send your set of elements in an array like so:
var elementIntervals = [];
function animateElements(elementArray)
{
for(var j = 0; j < elementArray; j++)
{
(function(element, index)
{
elementIntervals[index] = setTimeout(function()
{
slideDown(element, index);
}, 15 + (100 * index));
})(elementArray[j], j);
}
}
function slideDown(sliding, index)
{
sliding.style.height = parseInt(sliding.style.height)+5+'px';
if(sliding.style.height == "401px")
clearTimeout(elementIntervals[index]);
else
elementIntervals[index] = setTimeout(function()
{
slideDown(sliding, index);
}, 15);
}
I'm having some problems, I'd like to have a sort of slideshow where users have 4 buttons, and when they click one div appears and the others disappear. The div's are all in the same place with the same size. I'd also like to put this automatic
var Idx = 1;
var IntervalKey = setInterval = (auto, 5000);
var auto = function() {
$("#MainImage").eq(Idx).fadeIn(1000);
while(Idx <3) {
Idx++;
$("#MainImage").eq(Idx).hide();
}
Idx++;
if(Idx>3) {
Idx = 0;
}
};
$(".botao-imagem").click(function(){
Idx = $(".botao-imagem").index(this);
auto();
});
Your main issue is repeated IDs, IDs must be unique, so $("#ID").eq() doesn't every have a purpose really, since it should be 1 or 0 results. First give the elements a class instead:
<div class="MainImage"><p>111111</p></div>
<div class="MainImage"><p>222222</p></div>
<div class="MainImage"><p>333333</p></div>
<div class="MainImage"><p>444444</p></div>
and use a class selector, like this:
$(".MainImage")
Also auto needs to be declared before using it or define it as a function directly, overall like this:
var Idx = 0;
var IntervalKey = setInterval(auto, 5000);
function auto() {
$(".MainImage").hide().eq(Idx).fadeIn(1000);
Idx++;
if(Idx>3) Idx = 0;
};
$(".botao-imagem").click(function(){
Idx = $(".botao-imagem").index(this);
auto();
});
You can test the updated/working version with the above code here.