JS slider image disappears when clicking Prev/Next arrow - javascript

I've tried to look for a solution for this but have failed miserably. It's my first ever time using JS (I'm trying to learn) so the possibility of my just not understanding the answers in the search results properly is quite high - sorry about that.
I am wanting a JS carousel, generated from an array, with Prev/Next buttons (ideally responsive etc but that'll come at a later stage), preferably with captions underneath. I can get the carousel to work but I end up getting a text link when I click on either Prev or Next. And I've no idea how to add the caption array underneath (I've taken out the JS for the captions for now because it was messing everything else up even further).
Relevant HTML:
<body onload="changePilt()">
<span id="prev" class="arrow">❮</span>
<div class="karussell" id="karussell">
<img class="karu" name="esislaid">
</div>
<span id="next" class="arrow">❯</span>
<div class="caption">
<h3 name="esikiri"></h3>
</div>
</body>
CSS, just in case:
.karussell {
position: relative;
width: 100%;
max-height: 600px;
overflow: hidden;
}
.arrow {
cursor: pointer;
position: absolute;
top: 40%;
width: auto;
color: #00A7E0;
margin-top: -22px;
padding: 16px;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
border-radius: 0 3px 3px 0;
}
#next {
right: 0;
border-radius: 3px 0 0 3px;
}
#prev {
left: 0;
}
.arrow:hover {
background-color: rgba(0,0,0,0.8);
}
.caption {
text-align: center;
color: #00A7E0;
padding: 2px 16px;
}
.karu {
max-width: 75%;
}
#media (max-width:767px){.karu{max-width: 95%;}}
And finally, the dreaded JS:
var i = 0;
var s = 0;
var esileht = [];
var aeg = 5000;
//Image List
esileht[0] = 'img/tooted/raamat/graafvanalinn2016.jpg';
esileht[1] = 'img/tooted/kaart/kaart_taskus_esipool.jpg';
esileht[2] = 'img/tooted/kaart/graafkaart_esikylg.jpg';
//Change Image
function changePilt (){
document.esislaid.src = esileht[i];
if(i < esileht.length -1){
i++;
} else {
i = 0;
}
setTimeout("changePilt()", aeg);
}
document.onload = function() {
}
// Left and Right arrows
//J2rgmine
function jargmine(){
s = s + 1;
s = s % esileht.length;
return esileht [s];
}
//Eelmine
function eelmine(){
if (s === 0) {
s = esileht.length;
}
s = s -1;
return esileht[s];
}
document.getElementById('prev').addEventListener('click', function (e){
document.getElementById('karussell').innerHTML = eelmine();
}
);
document.getElementById('next').addEventListener('click', function (e) {
document.getElementById('karussell').innerHTML = jargmine();
}
);
I'm sure the solution is dreadfully obvious, I just cannot seem to be able to figure it out...

instead of innerHTML change src attribute of image
document.querySelector('#karussell img').src = eelmine();
And
document.querySelector('#karussell img').src = jargmine();

Related

I'm having trouble displaying an html button with javascript

I have two buttons on an HTML page, and I'm trying to show them once a button is pressed, but only one actually displays.
This is the HTML
<button onclick="testLeft()" class="item-description" id= "left-item-description">.</button>
<button onclick="testRight()" class="item-description" id= "right-image-description">.</button>
This is the CSS
.item-description {
display: none;
box-sizing: border-box;
position: fixed;
z-index: 4;
font-size: 35px;
font-weight: 600;
height: auto;
top: 30%;
padding: 10px 10px;
color:white;
background-color: transparent;
border-radius: 4px;
border: 3px solid black;
transition: all 0.2s ease;
}
#left-item-description {
margin-left: 10%;
margin-right: 60%;
}
#right-image-description {
margin-right: 10%;
margin-left: 60%;
}
And this is the javascript
function newGame(){
score = -1;
increaseScore();
correct = true;
for (let i = 0; i < used.length; i++){
used[i] = false;
}
indexLeft = shuffleIndex();
indexRight = shuffleIndex();
var left = document.getElementById("left-item-description");
var righ = document.getElementById("right-item-description");
left.style.display = "block";
left.innerText = items[indexLeft];
document.getElementById("left-item-image").src=images[indexLeft];
righ.style.display = "block";
righ.innerText = items[indexRight];
document.getElementById("right-item-image").src=images[indexRight];
}
The left button works perfectly how I want it to, but for some reason, the right button doesn't display
The element ID for your right button is "right-image-description" but in your Javascript you are trying to get "right-item-description".
change the id attribute from this:
var righ = document.getElementById("right-item-description");
to
var righ = document.getElementById("right-image-description");
and it should work.

Create a +1 Animation when button is clicked

I was making a game where you get money for clicking on a button. Here's a part of it:
var money = 0;
var currentMoney = document.getElementById("currentMoney");
function addOne() {
money++;
currentMoney.innerHTML = money;
}
<button onclick="addOne();">+1$</button>
<p>Money: <b id="currentMoney">0</b>$</p>
Later i was looking in the Internet and i found a website called Cookie Clicker and i saw this animation that when you click the cookie, a +1 is going up and fades away (It is not so important that the number goes up where the mouse is for my example):
I tried making this animation but i don't know how i can make it go up:
var money = 0;
var currentMoney = document.getElementById("currentMoney");
function addOne() {
money++;
currentMoney.innerHTML = money;
var moneyAnimation = document.createElement("p");
moneyAnimation.innerHTML = "+1";
document.getElementById("moneyAnimation").appendChild(moneyAnimation);
}
* {
margin: 0;
padding: 0;
}
#moneyAnimation {
height: 500px;
border: 1px solid;
width: 200px;
float: right;
}
<button onclick="addOne();">+1$</button>
<p>Money: <b id="currentMoney">0</b>$</p>
<div id="moneyAnimation"></div>
Thanks in advance, have a nice day! :)
I would recommend using CSS animation like below.
You can read more about keyframe animation here and here
var money = 0;
var currentMoney = document.getElementById("currentMoney");
function addOne() {
money++;
currentMoney.innerHTML = money;
var moneyAnimation = document.createElement("p");
moneyAnimation.innerHTML = "+1";
document.getElementById("moneyAnimation").appendChild(moneyAnimation);
moneyAnimation.classList.add("moneyAnimation"); // Add the class that animates
}
* {
margin: 0;
padding: 0;
}
#moneyAnimation {
height: 500px;
border: 1px solid;
width: 200px;
float: right;
position: relative; /* Added */
}
#keyframes moneyAnimation {
0% {
opacity: 1;
top: 0;
}
100% {
opacity: 0;
top: -50px;
}
}
.moneyAnimation {
animation: moneyAnimation 1s forwards;
position: absolute;
}
<button onclick="addOne();">+1$</button>
<p>Money: <b id="currentMoney">0</b>$</p>
<div id="moneyAnimation"></div>

Using getBoundingClientRect() when resizing the window

I have this navbar and everytime I click an option in the navbar the absolute positioned indicator gets the position of the option on the left and the width with the help of getBoundingClientRect() and it is moved to the target.
The problem is when I resize the window the indicator changes it's position and moves away.To stay in the same place when I resize the window I applied an eventListener to the window and everytime is resized I get the new values of left and width with getBoundingClientRect().
It works but I wonder if that is a bad way to do it because of the calculations that happen everytime the window is resized and if that is the case what is a better way to do this.
Here is the code:
const navigator = document.querySelector('.navigator');
const firstOption = document.querySelector('.first-option');
const navOptions = document.querySelectorAll('.nav-option');
const nav = document.querySelector('nav');
navigator.style.left = `${firstOption.getBoundingClientRect().left}px`;
navigator.style.width = `${firstOption.getBoundingClientRect().width}px`;
nav.addEventListener('click', function(e) {
if(e.target.classList.contains('nav-option')) {
navOptions.forEach(option => option.classList.remove('nav-option-active'));
e.target.classList.add('nav-option-active');
navigator.style.left = `${e.target.getBoundingClientRect().left}px`;
navigator.style.width = `${e.target.getBoundingClientRect().width}px`;
};
});
window.addEventListener('resize', function() {
let navOptionActive = nav.querySelector('.nav-option-active');
navigator.style.left = `${navOptionActive.getBoundingClientRect().left}px`;
navigator.style.width = `${navOptionActive.getBoundingClientRect().width}px`;
});
* {
margin: 0;
padding: 0;
}
nav {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
margin: 100px auto;
padding: 7vh 30vw;
width: auto;
background:#eeeeee;
}
.nav-option {
padding: 0 15px;
font-size: 22px;
cursor: pointer;
}
.navigator {
position: absolute;
left: 0;
bottom: 0;
height: 5px;
background: orangered;
transition: .4s ease all;
}
#media (max-width: 1200px) {
.nav-option {
font-size: 18px;
padding: 10px;
}
}
<nav>
<div class="navigator"></div>
<div class="nav-option first-option nav-option-active">HOME</div>
<div class="nav-option">INFO</div>
<div class="nav-option">CONTACT</div>
<div class="nav-option">ABOUT</div>
<div class="nav-option">MENU</div>
</nav>
You can make your <nav> element tightly wrap the buttons, then position the underline relative to the <nav>. A new wrapper <div> around the <nav> takes care of the margins and gray background. Instead of getBoundingClientRect() you then need to use offsetLeft and offsetWidth.
Note that this doesn't handle the changes in response to your #media query. For that, you could add a resize listener that specifically only handles changes across the 1200px threshold. Alternatively, you could reparent the underline to be a child of the actual nav button while it's not animating. Neither solution is great, but both would get the job done.
const navigator = document.querySelector('.navigator');
const firstOption = document.querySelector('.first-option');
const navOptions = document.querySelectorAll('.nav-option');
const nav = document.querySelector('nav');
navigator.style.left = `${firstOption.offsetLeft}px`;
navigator.style.width = `${firstOption.offsetWidth}px`;
nav.addEventListener('click', function(e) {
if(e.target.classList.contains('nav-option')) {
navOptions.forEach(option => option.classList.remove('nav-option-active'));
e.target.classList.add('nav-option-active');
navigator.style.left = `${e.target.offsetLeft}px`;
navigator.style.width = `${e.target.offsetWidth}px`;
};
});
* {
margin: 0;
padding: 0;
}
.nav-wrapper {
margin: 100px 0;
display: flex;
justify-content: center;
background: #eeeeee;
}
nav {
position: relative;
display: flex;
}
.nav-option {
padding: 7vh 15px;
font-size: 22px;
cursor: pointer;
}
.navigator {
position: absolute;
left: 0;
bottom: 0;
height: 5px;
background: orangered;
transition: .4s ease all;
}
#media (max-width: 1200px) {
.nav-option {
font-size: 18px;
padding: 10px;
}
}
<div class="nav-wrapper">
<nav>
<div class="navigator"></div>
<div class="nav-option first-option nav-option-active">HOME</div>
<div class="nav-option">INFO</div>
<div class="nav-option">CONTACT</div>
<div class="nav-option">ABOUT</div>
<div class="nav-option">MENU</div>
</nav>
</div>
If you have to use getBoundingClientRect (which honestly has nothing wrong with it), you can throttle the call, so that only the last resize after sufficient time has passed will execute. There are zillion ways of doing this, I will leave one example:
window.onresize = (function(id = null, delay = 600, oEvent = null){
return function fire(event){
return (new Promise(function(res,rej){
if (id !== null){
oEvent = event;
rej("busy");
return;
}
id = setTimeout(function(){
res(oEvent || event);
},delay);
})).then(function(event){
id = null;
console.log(event, "do getBoundingClientRect call");
}).catch(function(){void(0);});
};
}());
Replace console.log with what you want to do.
Your other option is to switch to intersection observer, if you can restructure your rendering logic. That will require some work

Failing to get condition to work with div?

I want to have the ball sized to the prompt of the user upon entering it and something doesn't work, can't tell what I'm doing wrong.
<style>
body {
background-color: black;
text-align: center;
}
h1 {
color: white;
}
div {
width: 100px;
height: 100px;
margin: auto;
margin-bottom: 10px;
border-radius: 50%;
transition: 0.3s;
line-height: 50px;
.ball4 {
background-color: brown;
}
</style>
<div class="ball4" onclick="onBall4Click()">
PROMPT
</div>
<script>
function onBall4Click() {
var ball4 = document.querySelector('.ball4');
var ball4Size = prompt("Size of ball? ");
if (ball4Size > 1000) {
alert("Too big!")
} else {
var ball4Size = size;
}
}
</script>
Thanks in advance to the helpers.
I feel like this is what you want with your JavaScript:
function onBall4Click() {
var ball4 = document.querySelector('.ball4');
var ball4Size = prompt("Size of ball? ");
if (ball4Size > 1000) {
alert("Too big!")
} else {
ball4.style.width = ball4Size;
ball4.style.height = ball4Size;
}
}
You were using an undefined variable rather than setting the actual size of the element. Also, I believe you still need to make the element a ball at this point because it is just a brown div right now.

Flickr carousel stretching image HTML, CSS

please can some one help to figure out why the image not maintaining the aspect ratio. I've was looking for a Flickr script to my site and found one. But the main problem is that it cannot maintain the aspect ratio.
Please help me obi wan, you are my last hope!
Script was found in this site:
https://github.com/blackfalcon/flickr-carousel/blob/master/index.html
To help identify the issues i've uploaded it to my site as index2:
http://scorpion3d.com/index2.html
<!doctype html>
<html lang="en" dir="ltr">
<head>
<title>Flickr API Carousel</title>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link href="https://fonts.googleapis.com/css?family=EB+Garamond" rel="stylesheet">
<style>
html,
body {
height: 100%;
margin: 0;
font-family: 'EB Garamond', serif;
}
html {
box-sizing: border-box;
}
body {
background-color: rgba(0,0,0,0.5);
}
*, *:before, *:after {
box-sizing: inherit;
}
a {
color: white;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.carousel-box {
height: 100%;
overflow: hidden;
}
.action-buttons {
width: 100%;
display: flex;
justify-content: space-between;
position: absolute;
top: calc(50% - 100px);
z-index: 1;
opacity: .1;
transition: opacity .25s ease;
}
.carousel-box:hover .action-buttons {
opacity: 1;
}
.action-buttons button {
border: none;
font-size: 50px;
padding: 0 10px;
display: block;
background-color: rgba(255,255,255,.5);
height: 1.2em;
line-height: 1;
}
.action-buttons button:hover {
cursor: pointer;
}
.carousel-content {
height: 100%;
display: flex;
align-items: center;
}
[data-function="slide"] {
position: absolute;
width: 100%;
height: 100%;
text-align: center;
opacity: 0;
transition: opacity .25s ease;
display: flex;
align-items: flex-end;
}
[data-function="slide"] p {
letter-spacing: 3px;
padding: 1rem 40px;
width: 100%;
color: white;
font-size: 2.5rem;
z-index: 10;
margin: 0 auto;
background-color: rgba(0,0,0,0.3);
}
.carousel-content img {
position: fixed;
top: 0;
bottom: 0;
left: -90%;
right: 0;
height: 100%;
overflow: auto;
}
[data-function="slide"].current-slide {
opacity: 1;
}
.album-info {
color: white;
position: absolute;
background-color: rgba(0,0,0,0.3);
font-size: 1rem;
z-index: 10;
width: 100%;
padding: 1rem;
}
.album-info > a {
margin-right: 1rem;
padding-right: 1rem;
border-right: 1px solid white;
}
#media screen and (min-width: 568px) {
.carousel-content img {
left: 0;
width: 100%;
overflow: auto;
}
}
#media screen and (min-width: 768px) {
.action-buttons button {
font-size: 100px;
}
}
</style>
</head>
<body>
<div class="carousel-box" id="carouselBox">
<div class="action-buttons">
<button class="prev" aria-hidden="true" tabindex="-1" title="use left arrow key">
❮
</button>
<button class="next" aria-hidden="true" tabindex="-1" title="use right arrow key">
❯
</button>
</div>
<div class="album-info">
<a id="albumLink" target="_blank"><span id="albumInfo"></span></a>
<span>Photos by <a id="albumOwnerLink" target="_blank"><span id="owner"></span></a></span>
</div>
<div class="carousel-content" id="carouselContent"></div>
</div>
<script type="text/javascript">
// Flickr configurations
// Obfuscated API key var for demo
const _0x6e6e=["\x65\x66\x63\x38\x33\x64\x63\x63\x64\x37\x63\x31\x64\x30\x61\x65\x39\x33\x66\x34\x61\x61\x37\x61\x66\x62\x39\x37\x31\x66\x63\x65"];const apiKey=_0x6e6e[0]
// To personalize app, replace with your own API key
// const apiKey = '';
const album = '72157688964206172',
albumOwner = '154845055#N05',
flickrUrl = 'https://api.flickr.com/services/rest/',
method = '?method=flickr.photosets.getPhotos&api_key=',
perPage = '20',
formatCallback = '&format=json&nojsoncallback=1',
contentContainer = document.getElementById('carouselContent'),
oReq = new XMLHttpRequest();
// Handle a response from the Flickr API
function reqListener () {
const flickrPhotos = JSON.parse(this.responseText);
console.log(flickrPhotos.photoset);
// Parse response for album and owner information
const ownerName = flickrPhotos.photoset.ownername,
albumTitle = flickrPhotos.photoset.title,
albumUrl = 'https://www.flickr.com/photos/' + albumOwner + '/albums/' + album,
albumOwnerUrl = 'https://www.flickr.com/photos/' + albumOwner;
// append response data to HTML DOM elements
albumInfo.innerHTML = albumTitle;
owner.innerHTML = ownerName;
albumLink.href = albumUrl;
albumOwnerLink.href = albumOwnerUrl;
// Iterate through flickrPhotos in the response
flickrPhotos.photoset.photo.forEach(function(foto) {
// Generate the URL for individual photo based on template
const url = 'https://farm' + foto.farm + '.staticflickr.com/' + foto.server + '/' + foto.id + '_' + foto.secret + '.jpg';
const photoTitle = foto.title;
// Generate the necessary slide markup
// <span data-function="slide">
// <p>title</p>
// <img src="" />
// </span>
const span = document.createElement('span'),
img = document.createElement('img'),
title = document.createElement('p');
// append response data to generated HTML DOM elements
img.src = url;
img.alt = photoTitle;
title.innerHTML = photoTitle;
span.dataset.function = 'slide';
span.appendChild(title);
span.appendChild(img);
// Now append the new slide to the slide container
contentContainer.appendChild(span);
});
// Remote API request has been made and processed, initialize the carousel.
flickrCarousel();
}
// API call to Flickr
oReq.addEventListener("load", reqListener);
oReq.open("GET", flickrUrl + method + apiKey + '&photoset_id=' + album + '&user_id=' + albumOwner + '&per_page=' + perPage + formatCallback);
oReq.send();
// Carousel function
function flickrCarousel () {
// set scoped variables
const carouselBox = document.getElementById('carouselBox'),
prev = carouselBox.querySelector('.prev'),
next = carouselBox.querySelector('.next'),
slides = carouselBox.querySelectorAll('[data-function=slide]'),
deck = slides.length;
let slide = 0,
currentSlide = slides[0];
// Find current slide of array and add selector
currentSlide.classList.add('current-slide');
// slider function
function pushSlide(flip) {
// Use value of array to find node and remove selector
currentSlide.classList.remove('current-slide');
// Using value of current slide, add flip value to determine next slide value
slide = slide + flip;
// allows for full rotation of carousel; if 0 set value to -1 of array length
if (flip === -1 && slide < 0) {
slide = deck - 1;
}
// allows for full rotation of carousel; if max length of array, set to 0
if (flip === 1 && !slides[slide]) {
slide = 0;
}
// determine active slide and add selector
currentSlide = slides[slide];
currentSlide.classList.add('current-slide');
}
// Bind click events to toggle buttons and pass in slide flip value
next.addEventListener('click', () => {
pushSlide(1);
});
prev.addEventListener('click', () => {
pushSlide(-1);
});
// Bind keyboard events to slide triggers
document.addEventListener('keydown', event => {
if( event.keyCode == 39 ) {
pushSlide(1);
}
if( event.keyCode == 37 ) {
pushSlide(-1);
}
});
};
</script>
</body>
</html>
You have mentioned the height of the image to be 100% while defining ".carousel-content img" class.Try as below :
.carousel-content img {
position: fixed;
top: 0;
bottom: 0;
left: -90%;
right: 0;
overflow: auto;
}
Edit
The general thing to be kept in mind while working with the image :
we must not change the proportion of the image to prevent it from being distorted. hence, we can work either on width or on height, keeping the other one set to "Auto".
Definitely, the image will settle itself according to what we have defined for its width and height. So if there won't be enough space to accommodate the whole image, the part of it will be cropped of ( or you say, stays hidden )

Categories