Change element index on click (both sides) - javascript

Im building a small feature. Basically on click "next" I need to loop through listOfImages, grab each src attribute and put it inside big image src. When "prev" is clicked - same but backwards. Its like super simple Lightbox. The only "thing" is that images are all around the page.
Structure looks like this:
<div class="box">
<div class="big-image">
<a href="somehref" class="picture">
<img src="some_src" data-index="0">
</a>
</div>
<div class="more-viewes">
<ul>
<li>
<a href="somehref" class="picture">
<img src="some_src" data-index="1">
</a>
</li>
<li>
<a href="somehref" class="picture">
<img src="some_src" data-index="2">
</a>
</li>
<li>
<a href="somehref" class="picture">
<img src="some_src" data-index="3">
</a>
</li>
<li>
<a href="somehref" class="picture">
<img src="some_src" data-index="4">
</a>
</li>
...
</ul>
</div>
</div>
At the moment js looks like this:
var listOfImages = document.getElementsByClassName("picture");
var listOfImagesAmount = document.getElementsByClassName("picture").length;
for ( i = 0; i < listOfImages.length; i++) {
//adding indexes in order to differentiate them
listOfImages[i].dataset.index = I;
//here im launching the big image with "right" "left arrows"
listOfImages[i].addEventListener("click", function(e){
var srcAttr = this.lastChild.getAttribute('src');
var elemIndex = this.dataset.index;
var currentIndex = parseInt(elemIndex);
//need to create html.
document.getElementsByTagName("body")[0].innerHTML += `<div id="img-popup-back"><</div><img id="fancyimg" src="`+ srcAttr +`" alt=""><div id="img-popup-next">></div>`;
//"next" click event
document.getElementById("img-popup-next").addEventListener("click", function(){
var searchedIndex = currentIndex + 1;
currentIndex = searchedIndex;
if(currentIndex >= galleryItemsAmount - 2){
currentIndex =- 1;
}
var checkElement = document.querySelector('[data-index="'+ searchedIndex +'"]');
console.log(checkElement);//on index 0 this line showing a tag with an image inside as it should be.
console.log(checkElement.lastChild); // but this one, on index 0, outputs "#text".
if(checkElement){
var nextSrc = checkElement.lastChild.getAttribute('src');
}
console.log(nextSrc);
document.getElementById('fancyimg').setAttribute('src', nextSrc);
});
//"prev" click event
document.getElementById("img-popup-back").addEventListener("click", function(){
var searchedIndex = currentIndex - 1;
currentIndex = searchedIndex;
console.log(currentIndex);
if(currentIndex < galleryItemsAmount - 2){
currentIndex =+ 1;
}
var checkElement = document.querySelector('[data-index="'+ searchedIndex +'"]');
if(checkElement){
var nextSrc = checkElement.lastChild.getAttribute('src');
}
console.log(nextSrc);
document.getElementById('fancyimg').setAttribute('src', nextSrc);
});
e.stopPropagation();
e.preventDefault();
});
}
There is a problem that I can't solve at the moment. So:
document.getElementById("img-popup-next").addEventListener("click", function(){
works fine until it hits element which index is 0. At this moment console is showing that:
checkElement.lastChild.getAttribute is not a function.
Element exist. Data-attribute is = 0. Cant see what the problem is.
If im clicking again - fine. It goes on.
Here is the same:
document.getElementById("img-popup-back").addEventListener("click", function(){
But I also would like to know how to start from the end of my HTMLCollection as soon as im on element index 0.
There is also one sad thing. IE 11 support is required

It appears you are relying on all of your html tags to store the data about your images.
You might be better off if you store the details of your images in javascript objects in an array.
For example
var imageDataArray = [];
var imgObj = {
thumb_source: "/images/thumbs/000123.jpg",
fancy_source: "/images/fancy/000123.jpg"
}
imageDataArray.push(imgObj);
I only inserted a single object into the array, but your onLoad function could populate all of your image objects into that array. You'll notice that each object had src for both a thumbnail and a fancy
Then, rather than recreate the fancy img and the prev / next buttons... create them once in your html directly
<body>
<div id="fancyImgContainer">
<button id="prevBtn" onClick="imageShift(false)">Previous</button>
<img id="fancyImg" src="">
<button id="nextBtn" onClick="imageShift(true)">Next</button>
</div>
<div id="thumbContainer">
</div>
</body>
With that framework in mind, lets you can populate your thumbnails in your onLoad script by doing the following:
var thumbContainer = document.getElementById("thumbContainer");
for(var imgIndex = 0; imgIndex < imageDataArray.length; imgIndex++){
var element = document.createElement("img");
element.setAttribute('src',imageDataArray[imgIndex].thumb_source);
element.setAttribute('onclick', 'setFancyImage(' + imgIndex + ')');
thumbContainer.appendChild(element);
}
That should load up all of your thumbnails into the DOM. Next, lets tackle the setFancyImage(index) function
var currentIndex = 0;
function setFancyImage(index){
currentIndex = index;
var fancyImg = document.getElementById('fancyImg');
fancyImg.src = imageDataArray[currentIndex].fancy_source;
}
So now, when a thumbnail is clicked the fancy image src is updated. Next we tackle the prev and next buttons by writing the imageShift(next) function
function imageShift(next){
var numImages = imageDataArray.length;
var shiftedIndex = 0;
if(next){
shiftedIndex = (currentIndex + 1) % numImages;
} else {
shiftedIndex = currentIndex - 1;
if(shiftedIndex < 0){
shiftedIndex += numImages;
}
}
setFancyImage(shiftedIndex);
}
Now when either prev or next button is called, the function calls the setFancyImage() function but passes in the next or previous index. At index = 0, if they click previous, it will see that the result is less than 0 and will set it to be the last index (ie numImages - 1). If index is the last image and they click next, because the index will equal numImages, by taking % numImages the result will put shiftedIndex at 0.
Obviously all this is just concept... you'd need to adapt for your data and clean up the styling and what not

Related

Random images flickering during slideshow using reddit json api

Goal:
Photo slider where you can toggle between different subreddits and view recent photos which have been posted.
Issue:
When you select one subreddit (via dedicated button) and scroll through a few photos (forward and/or back) all works fine, however if you then choose a different subreddit (via dedicated button) and scroll through a few photos (forward and/or back) the photos from the prior/first subreddit you previously selected flicker in and out at seemingly random intervals. I have watched console while this happens and src url for whatever photo that flickers in/out never enters the img element (unless its happening too fast to catch), instead the src url goes directly to the expected image. Also, I am console logging the array of image urls as the sub is selected via click and there is no abnormalities (all the photo links in the array are from the correct subreddit and in the correct order).
What I have tried:Moving the empty array var into the loop itself and the if statement, moving the counter variable into the functions themselves, as well as wrapping the entire click function in a separate function. None of these attempts made any difference.
JS:
function reply_click(clicked_id) {
var trys = [];
var title = document.getElementById("red-sub");
title.innerHTML = clicked_id;
$.getJSON("https://www.reddit.com/r/"+ clicked_id +"/.json", function(result){
for (var i = 0; i < result.data.children.length; i++) {
var imagesOnly = result.data.children[i].data;
if(imagesOnly.thumbnail !== 'self' && imagesOnly.post_hint === 'image'){
var items = result.data.children[i].data.url;
trys.push(items);
console.log(items);
var s = 0; // Start Point
function setImage(){
document.slide.src = trys[s];
}
setImage();
function changeImg(){
// Check If Index Is Under Max
if(s < trys.length - 1){
// Add 1 to Index
s++;
} else {
// Reset Back To O
s = 0;
}
setImage();
}
function changeBack(){
if(s < trys.length - trys.length + 1){
s = trys.length -1;
} else {
s--;
}
setImage();
}
}
}
console.log(trys);
document.getElementById ("btngo").addEventListener ("click", changeImg, true);
document.getElementById ("btnback").addEventListener ("click", changeBack, true);
});
}
document.getElementById("cats").addEventListener ("click", function(event)
{reply_click(event.target.id);;
});
document.getElementById("architecture").addEventListener ("click", function(event)
{reply_click(event.target.id);
});
HTML:
<body>
<div class="container">
<div class="entry-header">
<h1>subreddit slide shows</h1>
<p>Click the buttons below to browse through the latest photos of each noted subreddit.</p>
</div>
<div class="red-buttons">
<button id="cats">cats</button>
<button id="architecture">architecture</button>
</div>
<div class="main">
<div class="main_cat">
<div class="main_section">
<h2>r/<span id="red-sub">?????</span></h2>
<div class="img_container">
<img name="slide" class="cat_img" style=""
src="https://cdn.worldvectorlogo.com/logos/reddit-2.svg" />
</div>
<div class="button_base">
<button id="btnback"><</button>
<button id="btngo">></button>
</div>
</div>
</div>
</div>
</div>
</body>

How to change an image every 5 seconds for example?

I have three images in my HTML code, and I want them to change every five seconds. Why does my code not work?
var images = [];
images[0] = ['photoFromInternet'];
images[1] = ['photoFromInternet2'];
images[2] = ['photoFromInternet3'];
var index = 0;
function change() {
document.mainPhoto.src = images[index];
if (index == 2) {
index = 0;
} else {
index++;
}
setInterval(change(), 1000);
}
window.onload = change();
<div class="lastMain">
<a href="www.comingsoon.com" id="slider">
<img id="mainPhoto">
<div class="mainSlider">
<img src="photoFromInternet1" style="display: none">
<img src="photoFromInternet2*" style="display: none">
<img src="photoFromInternet3" style="display: none">
</div>
</a>
</div>
P.S. If you can help please don't use jquery because I haven't learned that yet.
you should run 'change' function outside of the func and pass the function name to the setInterval func as below
let images = ['photoFromInternet', 'photoFromInternet2', 'photoFromInternet3'];
let index = 0;
const imgElement = document.querySelector('#mainPhoto');
function change() {
imgElement.src = images[index];
index > 1 ? index = 0 : index++;
}
window.onload = function () {
setInterval(change, 5000);
};
Look at your console, it's telling you why. Uncaught TypeError: Cannot set property 'src' of undefined, meaning document.mainPhoto is undefined. That's not how you select an element in JS (document.getElementById("mainPhoto") works better :)
Also, you should pass a function to setInterval, not call the function directly inside of it, otherwise you are infinitely calling change() which leads to an infinite call stack error.
Also, if you want 5 seconds, you want to pass 5000, not 1000 (milliseconds).
Finally, you want to set a timeout, not an interval, every time you call the function. Timeouts are executed once. If you set a new interval every time, you'll be piling up function calls exponentially, quickly making your page unresponsive by overwhelming the CPU.
var images = [];
images[0] = ['photoFromInternet'];
images[1] = ['photoFromInternet2'];
images[2] = ['photoFromInternet3'];
var index = 0;
function change() {
document.getElementById("mainPhoto").src = images[index];
if (index == 2) {
index = 0;
} else {
index++;
}
setTimeout(change, 5000);
}
window.onload = change();
<div class="lastMain">
<a href="www.comingsoon.com" id="slider">
<img id="mainPhoto">
<div class="mainSlider">
<img src="photoFromInternet1" style="display: none">
<img src="photoFromInternet2*" style="display: none">
<img src="photoFromInternet3" style="display: none">
</div>
</a>
</div>

issue: image carousel skips 1st image

I have an automatic image carousel in javascript for my html website. The carousel has 5 images. The carousel works well on the first round, but on the second round of images, the 1st image doesn't appear. I'm not sure why? Please help if you can
<script>
(function(){
var imgLen = document.getElementById('gallery');
var images = imgLen.getElementsByTagName('img');
var counter = 1;
if(counter <= images.length){
setInterval(function(){
images[0].src = images[counter].src;
console.log(images[counter].src);
counter++;
if(counter === images.length){
counter = 1;
}
},5000);
}
})();
</script>
It works the first time because your first image, which I'm assuming is the displayed image, starts with the correct source.
It appears that you are overwriting the source of this image with the other sources. After the first round, the original source of the first image is lost.
At the moment, your image sources are probably something like:
1,2,3,4,5
2,2,3,4,5
3,2,3,4,5
4,2,3,4,5
5,2,3,4,5
for the first round, which is alright. Once the second round starts however, and for subsequent rounds, it would go something like this:
2,2,3,4,5
3,2,3,4,5
4,2,3,4,5
5,2,3,4,5
The simplest solution would be to store the first image as a 6th image, which would work with your existing code.
An alternative solution would be to store image sources in a JavaScript variable and use those as sources instead of referencing other elements.
It seems that your first image in the set images[0] has its src attribute overwritten every time the setInterval runs, so its source value has been lost. This means it won't be readable again. Rather than using the 0th item in the set to be the display target for your slideshow, try giving it a unique classname (<img class="slideshowTarget" src="...">) and selecting it individually like:
var slideshowTargetImage = document.querySelector('.slideshowTarget');
Rather than using imgLen.getElementsByTagName('img'), try adding a classname to the images you want to cycle in (<img class="slideshowImage" src="...">) and select them with something like:
var images = document.querySelectorAll('.slideshowImage');
Next, you'll want the image list to contain the original image again, or it won't be available in your image list. You should put that item at the end, so it'll be in the correct position when it's time for your slideshow to loop.
<div class="slideshow">
<img class="slideshowTarget" src="0.jpg" />
<div class="slideshowPreloadImages" style="display: none;">
<img class="slideshowImage" src="1.jpg" />
<img class="slideshowImage" src="2.jpg" />
<img class="slideshowImage" src="3.jpg" />
<img class="slideshowImage" src="0.jpg" />
</div>
</div>
Next, you can simplify your logic for the loop into one statement that you can run after you set the source on your image. The %, or "modulo" operator causes the counter to wrap back around to zero as soon as it grows past images.length - 1.
counter = (counter + 1) % images.length;
All together!
(function(){
var slideshowTargetImage = document.querySelector('.slideshowTarget');
var images = document.querySelectorAll('.slideshowImage');
var counter = 0;
var cycleSlideshow = function(){
var nextImageSource = images[counter].src;
slideshowTargetImage.src = nextImageSource;
console.log('nextImageSource', nextImageSource);
counter = (counter + 1) % images.length;
};
if (images.length) { // we can now test whether it's 0/falsy, becacuse the target is not part of the set!
setInterval(
cycleSlideshow,
1000
);
}
})();

Switching image with Next/Previous buttons

Is there any way to switch images using next/prev buttons with jQuery? Here's the code:
<div class="prevDiv">
<img src="images/prev.png" alt="previous" />
</div>
<div class="pic" id="picwebd">
<img src="images/portfolio/webdesign/webd1.jpg" class="portPic" />
</div>
<div class="nextDiv">
<img src="images/next.png" alt="previous" />
</div>
I tried modifying this code to my needs: http://jsfiddle.net/x5mCR/16/ but I haven't succeed. I think that incrementing and decrementing number in the image src would be enough, but I can't come up with decent code do this. Google doesn't help neither.
In case anyone reading this post want a different approach still using JQuery fadeIn, Im posting below the code for that.
Here you can find the fiddle for it.
Here's the Javascript Part
//At the start will show the first image
$('#fullimage img.fullimage:first-child').fadeIn();
//Keep track of the image currently being visualized
var curr = $('#fullimage img.fullimage:first-child');
$('#next').on('click', function() {
//Hide Current Image
curr.hide();
//Find Next Image
var next = curr.next();
//If theres no next image (is the last img), go back to first
if (next.length == 0) next = $('#fullimage img:first');
//Fade In
next.fadeIn();
//Save in curr the current Image
curr = next;
return false;
});
$('#prev').on('click', function() {
curr.hide();
var prev = curr.prev();
if (prev.length == 0) prev = $('#fullimage img:last');
prev.fadeIn();
curr = prev;
return false;
});
Here's the HTML part
<div id="fullimage">
<img class="fullimage" src="http://i.imgur.com/RHhXG.jpg" />
<img class="fullimage" src="http://i.imgur.com/p1L2e.jpg" />
<img class="fullimage" src="http://i.imgur.com/NsrI0.jpg" />
<img class="fullimage" src="http://i.imgur.com/Ww6EU.jpg" />
</div>
<label id="prev">previous</label>
<label id="next">next</label>
Here is dynamic and simple script reducing your html code
http://jsfiddle.net/x5mCR/32/
$("#thumbnail a").on('click', function (eve) {
eve.preventDefault();
var link = ($(this).attr("href"));
var content = '<img src="' + link + '"/>';
$("#fullimage").hide().html(content).fadeIn('slow');
});
Remove the anchors with class thumbnail and give the corresponding <img> tags the thumbnail class, then use jQuery click methods for the thumbnail class:
$(".thumbnail").click(function() {
$(".fullimage").src = $(this).attr("src");
});
Make sure you have a single .fullimage in the #fullimage div.
This isn't the same as a next / previous button - but it would fix the JSFiddle that you made.
http://jsfiddle.net/x5mCR/34/
var picNumber = 1;
$(".nextDiv").click(function() {
picNumber++;
if (picNumber > 3) picNumber = 1; // Change 3 to how many pictures there are.
$(".pic img").attr("src", "images/portfolio/webdesign/webd" + picNumber + ".jpg");
});
$(".prevDiv").click(function() {
picNumber--;
if (picNumber < 1) picNumber = 3; // Change 3 to how many pictures there are.
$(".pic img").attr("src", "images/portfolio/webdesign/webd" + picNumber + ".jpg");
});
If I understand correctly, you're trying to use the arrow keys to move back and forth between pictures...so if this is the case, I would recommend taking a look at this post: Binding arrow keys in JS/jQuery
Also, for your convenience, I just took the code from that post and combined it with the function in your fiddle to get this:
$(document).keydown(function (e) {
if (e.keyCode == 39) {
$(".fullimage").hide();
var next = $(this).next();
if (next.length > 0) {
next.fadeIn();
} else {
$('#fullimage img:first').fadeIn();
}
return false;
}
});
In testing it looks like it might need some modification, and also, you would obviously need to create a similar function for when the back button is pressed, but I think if I'm understanding your issue correctly this is a good starting place.

Errors writing image gallery

I'm trying to write a simply image gallery element for a website and I'm having trouble with the code for silly reasons. I've never gotton on with JavaScript and have always found it a headache. I've tried various other image galleries but can't for the life of me get them to actually work correctly either
My current HTML code is like this:
<!DOCTYPE html>
<html>
<head>
<title> Test of slider </title>
<script type="text/javascript" src="slider.js"></script>
</head>
<body>
<div class="slider" id="main">
<img src="#" class="mainImage" />
<div class="sliderImages" style="display: none;">
<img src="companion.jpg"/>
<img src="cookie.jpg" />
<img src="orange.jpg" />
<img src="orangeWhole.jpg" />
</div>
<div class="sliderButtons">
Previous
Next
</div>
</div>
</body>
</html>
with the javascript like this:
this.Slider = new function(){
// Stores the indices for each slider on the page, referenced by their ID's
var indices = {};
var limits = {};
var images = {};
// Call this function after a major DOM change/change of page
this.SetUp = function(){
// obtain the sliders on the page
// TODO restrict to those within body
var sliders = document.getElementsByClassName('slider');
// assign the indices for each slider to 0
for(var i = 0; i < sliders.length; i++){
indices[sliders[i].id] = 0;
var sliderImages = document.getElementsByClassName('sliderImages');
var imagesTemp = sliderImages[0].getElementsByTagName('img');
images[sliders[i].id] = imagesTemp;
limits[sliders[i].id] = imagesTemp.length;
}
}
// advances a certain slider by the given amount (usually 1 or -1)
this.Slide = function(id, additive){
if(indices && id){
indices[id] = indices[id] + additive;
// Check limits
if(indices[id] < 0){
indices[id] = limits[id] - 1;
}
if(indices[id] >= limits[id]){
indices[id] = 0;
}
// alter img to be the new index
document.getElementById(id).getElementsByClassName('mainImage')[0].src = images[id][indices[id]].src;
}
}
}
for(var slider in sliders)
{
// here slider is the index of the array. to get the object use sliders[slider]
}
then you can use 'getElementsByClassName' function
edit
U have included the slider.js on the top of the html. So first it loads the the js and tries to access the elements which are not yet created..Move the tag to the bottom of the page.
sliderImages is an array of divs with classname sliderImages. there is only one that satisfies.
var sliderImages // is a array with 1 item.
// to get the images use sliderImages[0].getElementsByTagName('img');
change
this.Slide = new function(id, additive){
to
this.Slide = function(id, additive){ // otherwise it will be called when the page is loaded with undefined values.
onclick of the link call with quotes
Slider.Slide('main', 1)
You are using a methode I do not know (or you forgot the "s")
var sliderImages = slider.getElementByClassName('sliderImages');
I would use something like the code below. It is important sliderImages will be an array of anything that is of the class "silderImages"
var sliderImages =slider.getElementsByClassName("sliderImages")

Categories