Random images flickering during slideshow using reddit json api - javascript

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>

Related

Change element index on click (both sides)

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

Targeting HTML ID's and using jQuery to modify the content

I have this photo switcher below that I want to modify the HTML content using jQuery only. If you click on the "Show Next Photo" link jQuery will replace the "fruits.png" with another image example "airplane.png". (note: No changes to the HTML block is allowed).
I'm not sure how complicated it can be for jQuery. If I could avoid JavaScript, would be perfect.
<!--Do Not Change Inside this DIV-->
<div id="imageSwitcher">
<img src="https://homepages.cae.wisc.edu/~ece533/images/fruits.png" id="fruits" />
<img src="https://homepages.cae.wisc.edu/~ece533/images/tulips.png" id="tulips" style="display:none;" />
<p>Show Next Photo</p>
</div>
Problem:
This is my script below and isn't working properly because when I refresh the page it just shows the airplane.png, and if I click on the link "Show Next Photo" it makes the airplane disapear.
Please give it a try at https://codepen.io/mrborges/pen/QQjJOq
<script>
//Go away fruits.png
document.getElementById('fruits').style.cssText = "display:none;";
$(document).ready(function () {
$('p').click(function () {
$('#imageSwitcher img').attr("src", "https://homepages.cae.wisc.edu/~ece533/images/airplane.png");
//$('#fruits').toggle("hide");
$('#tulips').toggle("slow");
})
});
</script>
<script>
$(document).ready(function () {
let count = localStorage.getItem('count') || 0; // "0, 1, 2" or 0
count = parseInt(count, 10); //If we get it from storage then convert to number
const images = [
"https://homepages.cae.wisc.edu/~ece533/images/fruits.png",
"https://homepages.cae.wisc.edu/~ece533/images/tulips.png",
"https://homepages.cae.wisc.edu/~ece533/images/airplane.png"
];
$('#fruits').attr("src", images[count]);
$('p').click(function () {
count = (count + 1) % images.length;
$('#fruits').attr("src", images[count]);
localStorage.setItem('count', count);
});
});
</script>
The const images is a list (array) of links to the switch between. I added all the possible images and then i just change the src for each image. a pure jQuery solution would be very ugly, so you have to accept some vanilla JavaScript.
this line count = (count + 1) % images.length counts 1 up each time you click on the <p> if we reach the end of the images, then it just resets to 0. e.g. (2 + 1) % 3 = 0

Multiple Id's calling on same JavaScript function

I am trying out a JavaScript where it takes Id of an image and onclick of the image it performs some function. But I have multiple Id's of same image where the id of the onclick'ed image should be processed by JavaScript and the operation should be performed.
Problem is I am not able to get the right id based on the click.
here is my code
1)myhtml
<div class="col-md-3 col-sm-6">
<div class="sub-process-block quantity">
<h3>choose quantity</h3>
<div id="example" onclick="changeImage()">
<img src="img/carton-empty.png" id="myImage">
<img src="img/carton-empty.png" id="myImage1">
<img src="img/carton-empty.png" id="myImage2">
</div>
</div>
2)javascript
<script>
function changeImage() {
var imageArray=["myImage","myImage1","myImage2"];
for(var i=0;i<imageArray.length;i++ ){
image = document.getElementById(imageArray[i]).onclick;
}
if(image.src.match("selected")) {
image.src="img/carton-empty.png";
}else{
image.src = "img/carton selected.png";
}
}
Why don't you add an event listener to your images in JS? Then you can check if it's selected or not and update the source accordingly
// get all images and put them in an array
var images = [].slice.call(document.querySelectorAll('img'));
// loop through images and add event listener
images.forEach(function(image) {
image.addEventListener('click', onImageClick);
});
// on click, check if image is selected and update src
function onImageClick(e) {
var image = e.target;
if (image.src.match("selected")) {
// is selected, now unselected it and update src
image.setAttribute('src', 'img/carton-empty.png');
} else {
// is not selected, now select it and update src
image.setAttribute('src', 'img/carton selected.png');
}
}
https://jsfiddle.net/0qzdsf8r/4/
Inspect the image elements in the dev tools and see the class and src change.
Try this ;)
function changeImage(){
var imageArray = ["myImage", "myImage1", "myImage2"];
for(var i = 0; i < imageArray.length; i++){
var image = document.getElementById(imageArray[i]);
if(image.src.match("selected")){
image.src = "img/carton-empty.png";
}else{
image.src = "img/carton selected.png";
}
}
}
You placed condition outside for loop;

Spinning circle on click

I have a code where onclick a word on left side of the page, it shows some text on right hand side of page. Here's the jsfiddle of working code.
Now, my problem is I want to display spinning circle on page on every onclick and then show text on the right hand side of the page. My code for spinning circle is:
HTML:
<div id="loading">
<img src="http://jimpunk.net/Loading/wp-content/uploads/loading1.gif"/>
</div>
JavaScript:
function hideLoading() {
document.getElementById("loading").style.display = 'block';
}
function showLoading() {
document.getElementById("loading").style.visibility = 'visible';
}
CSS:
#loading {
display: none;
}
Now, I don't know how to place them in my working code to get the desired result. Anybody knows the correct way of doing it?
Desired result: onclick "abc" on left hand side, spinning circle should be displayed for 1 sec and then "I should be printed on left side" should be displayed. Again on clicking "mno", first spinning circle should be shown for 1 sec and then text "I should be printed on left side" will be displayed. The fiddle has working version of onclick.
You should use a single handler function on each element that will both hide and show the loading gif. Also, it's a good idea not to use getElementById on every call, so save it in a variable:
<div id="container">
<div id="header">
<h1>Main Title of Web Page</h1>
Here I am trying to split the webpage into two columns and display text.</div>
<div id="one">
<div id="loading">
<img src="http://support.snapfish.com/euf/assets/images/answer_images/SpinningWheel.gif" />
</div>
<div id="message"></div>
</div>
<div id="two"> <b>This is test one<br /></b>
<b>This is test two<br /></b>
</div>
Javascript:
var elements = {};
function loadSpanContent() {
elements.loading.style.display = 'block'; // Show loading gif
spanContent = this.innerHTML
setTimeout(function () {
elements.message.innerHTML = "I should be printed on left side - " + spanContent;
elements.loading.style.display = 'none'; // Hide loading gif
alert("onclick Event detected! " + spanContent);
}, 1000);
}
window.onload = function mydisplayArray() {
var array = ['abc', 'xyz', 'mno'];
elements.loading = document.getElementById("loading");
elements.one = document.getElementById("one");
elements.message = document.getElementById("message");
for (i = 0; i < array.length; i++) {
var span = document.createElement('span');
span.innerHTML = array[i];
span.onclick = loadSpanContent;
one.appendChild(span);
}
};
Here is a fiddle: http://jsfiddle.net/nBaCJ/1/
I'm still confused by what you actually want here, but if you want to have the loading message disappear after one second, you should use setTimeout. Something like this:
function showAlert() {
showLoading();
setTimeout(hideLoading,1000);
//Hide loading circle
var myString = "I should be printed on left side";
document.getElementById("two").innerHTML = myString;
}
But you also need to fix your "showLoading" and "hideLoading". Something like this:
function hideLoading() {
document.getElementById("loading").style.display = 'none';
}
function showLoading() {
document.getElementById("loading").style.display = 'block';
}
http://jsfiddle.net/7uxHC/9/
BTW: if you want your loading gif to appear over your content, then set its position:absolute in css, but note that you gif has a white, rather than transparent background so it will obscure your content.
Your request isn't clear.
But first, you should fix these 2 functions:
function hideLoading() {
document.getElementById("loading").style.display = 'none';
}
function showLoading() {
document.getElementById("loading").style.display = 'block';
}

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