I'm new to jQuery, practicing with a slideshow and trying to make it repeat. For some reason if ( last.is(active) ) is never returning true. In inspector I can see that the last child is getting the active ID. Is this not how it's meant to be used? if (active != last) didn't work either.
Fiddle
JS
function changeImage() {
var active = $('#active');
var first = $('#slideshow:nth-child(1)');
var last = $('#slideshow:nth-last-child(1)');
if ( last.is(active) ) {
var next = first;
} else {
var next = active.next();
}
next.attr('id', 'active');
active.attr('id', 'inactive');
}
setInterval(changeImage, 1000);
Markup
<div id="slideshow">
<img id="active" src="https://i.imgur.com/8iOuvtf.jpg">
<img src="https://i.imgur.com/Wi8mlH2.jpg">
<img src="https://i.imgur.com/MNhgqco.jpg">
</div>
CSS
#slideshow img {display: none;}
#slideshow #active {
display: block;
width: 100%;
height: auto;
}
I put this fiddle together for you.
https://jsfiddle.net/76xg0d7L/
It is much easier to work with classes than IDs in this situation. I have modified your changeImage() function.
function changeImage() {
var $next = $('.slide.active').removeClass('active').next('.slide');
if ($next.length) {
$next.addClass('active');
}
else {
$('.slide:first').addClass('active');
}
}
setInterval(changeImage, 1000);
I've also update your CSS to select the active class, as opposed to the ID.
#slideshow img {display: none;}
#slideshow .active {
display: block;
width: 100%;
height: auto;
}
Let me know if you have any questions or if this works for you.
You should use it more like
function changeImage() {
var active = $("[state='active']");
var next = active.is(":last") ? $("#slideshow:first-child") : active.next();
active.data("state", "inactive"); //don't multiply same id attribute
next.data("state", "active");
}
setInterval(changeImage, 1000);
https://jsfiddle.net/gm9twq6j/
You should pass around a class called "active" using .addClass, .removeClass, and .hasClass instead of what you are trying to do with swapping out IDs.
JS:
function changeImage() {
var active = $('#slideshow').find('.active');
var first = $('#slideshow img:first-child');
var last = $('#slideshow img:last-child');
if ( last.hasClass('active') ) {
var next = first;
} else {
var next = active.next();
}
active.removeClass('active');
next.addClass('active');
}
setInterval(changeImage, 1000);
CSS:
#slideshow img {display: none;}
#slideshow .active {
display: block;
width: 100%;
height: auto;
}
HTML:
<div id="slideshow">
<img class="active" src="https://i.imgur.com/8iOuvtf.jpg">
<img src="https://i.imgur.com/Wi8mlH2.jpg">
<img src="https://i.imgur.com/MNhgqco.jpg">
</div>
Related
I found (and tweaked) the code below that was designed for switching the larger img src with the src of thumbnails in a list, but I'm not sure how to adjust it to use something like https://picsum.photos/id/CLICKED_LI_textContent/200/200 as the URL instead of pulling from a thumbnail's src.
For some more context here's the original post in which I was looking into this
How can I change img src from list of (non-image) items?
I haven't taken any JS classes, so I'm not sure how every component of the script works. I'm more comfortable with pure HTML and CSS, but think JS is the answer for making this work more smoothly.
(I did add the jquery script src to the document for this)
Sorry the code is a little ugly, I would have added the script and style tags and such but I ran out of time while posting this
$("#list li").click(function(e) {
// if i use this getting undefined
// var src = $(this).attr("src");
// so i use this method
var target = e.target;
var src = target.src;
console.log(src);
$("#display").fadeOut(function() {
$(this).on('load', function() {
$(this).fadeIn();
});
$(this).attr("src", src);
});
//record which thumb was clicked
$("#list li").removeClass("active"); //remove class
$(this).addClass("active"); //apply class to selected thumb
});
//move next
$("#left-arrow").click(function() {
if ($("#list li.active").next("#list li").length > 0) {
$("#list li.active").next().children( 'img' ).trigger("click");
} else {
$("#list li:first > img").trigger("click"); //go to first
}
return false;
});
//move previous
$("#right-arrow").click(function() {
if ($("#list li.active").prev("#list li").length > 0) {
$("#list li.active").prev().children( 'img' ).trigger("click");
} else {
$("#list li:last > img").trigger("click"); //go to end
}
return false;
});
//click the first thumb to begin
$("#list li:first > img").trigger("click");
.container {
display: flex;
}
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/237/200/200" class="display" id="display">
</div>
</div>
Here is a pure javascript solution. The only difference is that it lacks the fading between the images.
I tried to write the code as pedagogic as possible, using variables as explanations. The code goes more with your original thread, where you had a bunch of images with different file endings. I gave the image an alt attribute, so you can see the change.
A short explanation:
Use an array for the images.
Create your list through javascript, using the array.
Add click listeners to your #list, where you read the .textContent. I added pointer-events: none; to any children to the li tags so they don't trigger the click listener.
Add click listeners to your prev/next buttons, where you check which index that the currently visible image has in the array (from 0 to 3 in imageArr) and then adds +1 och -1 to that index.
[edit] Added code for updating the CSS.
const listEl = document.getElementById('list');
const imgElement = document.querySelector('.right > img');
let imageArr = ["237.jpg", "240.gif", "100.jpeg", "301.png"]; // 1
let currentImage = '';
document.getElementById('next').addEventListener('click', () => shiftImage(1));
document.getElementById('prev').addEventListener('click', () => shiftImage(-1));
listEl.addEventListener('click', displayImage);
function updateImage(imageName) {
const subfolder = 'images/';
changeActive(imageName, currentImage); /* ADDED in EDIT */
currentImage = imageName;
imgElement.src = subfolder + imageName;
imgElement.alt = imageName;
}
/* ADDED in EDIT */
function changeActive(newImage, oldImage) {
if (oldImage) {
let oldIndex = imageArr.indexOf(oldImage);
toggleActiveClass(oldIndex);
}
let currentIndex = imageArr.indexOf(newImage);
toggleActiveClass(currentIndex);
}
/* ADDED in EDIT */
function toggleActiveClass(imageIndex) {
let liElements = listEl.childNodes;
liElements[imageIndex].classList.toggle('active');
}
function shiftImage(direction) {
let currentIndex = imageArr.indexOf(currentImage);
let newIndex = currentIndex + direction;
if (newIndex < 0) { newIndex = imageArr.length - 1; }
else if (newIndex >= imageArr.length) { newIndex = 0; }
let newImageName = imageArr[newIndex];
updateImage(newImageName);
}
function displayImage(event) {
let liElement = event.target;
updateImage(liElement.textContent);
}
function constructImageLinks() { // 2
let htmlOutput = '';
for (let imageSrc of imageArr) {
htmlOutput += `<li>${imageSrc}</li>`;
}
listEl.innerHTML = htmlOutput;
}
constructImageLinks();
updateImage(imageArr[0]);
section {
display: flex;
}
section ul {
margin-top: 0px;
}
section > .left li {
cursor: pointer;
padding: 0.25rem;
}
section > .left li.active {
background-color: pink;
}
section > .left li > * {
pointer-events: none;
}
section > div {
padding: 1rem;
}
section > .right > img {
width: 200px;
border: 1px solid;
padding: 0.5rem;
}
<section>
<div class="left">
<ul id="list"></ul>
<button id="prev">Previous</button>
<button id="next">Next</button>
</div>
<div class="right">
<img>
</div>
</section>
JSFiddle - Link
HTML
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/240/200/200" class="display" id="display">
</div>
</div>
Javascript
// HELPER FUNCTIONS
function getImageURL(id, width=200, height=200){
return "https://picsum.photos/id/"+ id + "/" + width + "/" + height;
}
function removeActive(){
let lis = $('#list li');
for(let i=0;i<lis.length;i++){
$(lis[i]).removeClass('active');
}
}
// HANDLE EVENTS
$(document).on('click', "#list li", async (e)=>{
await $('#display').fadeOut();
removeActive();
let li = $(e.target);
li.addClass('active');
let image_id = parseInt($(e.target).html());
let image_url = getImageURL(image_id);
$('#display').attr('src', image_url);
await $('#display').fadeIn();
});
//move next
$(document).on('click', "#left-arrow", (e)=>{
// Handler Here
});
//move previous
$(document).on('click', "#right-arrow", (e)=>{
// Handler Here
});
CSS
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
.container {
display: flex;
}
Can someone assist me with this? Whenever I try to scroll, the class none doesn't toggle..
window.addEventListener('scroll', function() {
var header = document.getElementsById("here");
header.classList.toggle("none", window.scrollY > 0);
});
.none {
display: none;
}
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/800px-Image_created_with_a_mobile_phone.png" id="here>
You simple didn't close id of img and write elementsbyid instead of elementbyid.
window.addEventListener('scroll', function() {
var header = document.getElementById("here");
header.classList.toggle("none", window.scrollY > 0);
});
.none {
display: none;
}
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/800px-Image_created_with_a_mobile_phone.png" id="here">
The thing is that I need to make a vertical images slider,so that when i press arrow down/arrow up every image changes it's position (the highest one goes bottom,the previous take it's place)
what it should look like:
what i have got so far:
$(function(){
var $vsliderboxes = $('#vsliderboxes'),
$vslidernav = $('#vslidernav'),
boxHeight = $vsliderboxes.height(),
current_index = 0;
function clickslide(){
clearInterval(intervalTimer);
clearTimeout(timeoutTimer);
timeoutTimer = setTimeout(function () {
intervalTimer = window.setInterval(autoslide, 2000);
}, 2500);
var index = $(this).index();
current_index = index;
$vsliderboxes.children().stop().animate({
top : (boxHeight * index * -1)
}, 500);
}
function autoslide(){
current_index++;
if (current_index >= $vsliderboxes.children().children().length) {
current_index = 0;
}
$vslidernav.find('a').eq(current_index).trigger('click');
}
$vslidernav.find('a').click(clickslide);
var intervalTimer = window.setInterval(autoslide, 2000),
timeoutTimer = null;
});
#vslidernav ul {
list-style: none;
padding: 0;
}
#vslidernav ul a {
padding: 0;
cursor: pointer;
height: 50px;
}
#vslidernav ul a:active {
color: #9C9A99;
}
#vslidernav ul a li {
height: 50px;
}
#vslidernav ul .active li {
}
.#vslidernav ul a:active {
background: transparent;
color: #9C9A99;
}
.vslider {
display: inline-block;
}
#vslidernav {
float: left;
width: 100px;
z-index: 1;
height: 250px;
}
#vsliderboxes {
position : relative;
overflow : hidden;
}
#vsliderboxes div {
height: 250px;
width: 900px;
}
#vsliderboxs-inner {
position : relative;
width : 900px;
height : 250px;
}
<div class="vslider">
<div id="vslidernav">
<ul>
<a id="1">
<li><img src="img/arrtop.gif"></li>
</a>
<a id="2">
<li><img src="img/arrdown.gif"></li>
</a>
<a id="3">
<li></li>
</a>
</ul>
</div>
<div id="vsliderboxes">
<div id="vsliderboxs-inner">
<div id="box1" class="active"><img src="img/slide1.gif"></div>
<div id="box2" class="inactive"><img src="img/slide2.gif"></div>
<div id="box3" class="inactive"><img src="img/slide3.gif"></div>
</div>
</div>
</div>
thanks for any advice
I think, that it isn't possible to solve this issue like you try to.
Because, when you work with the "top" property, you can't take one image from the top and append it to the other end because appending the image, will move the other images to another place --> the top property wouldn't be correct any more.
I think the contributed sliders (e.g. http://www.jssor.com/demos/vertical-slider.slider) work with the transform CSS property.
transform: translate3d()
Try to research about this property.
Roko C. Buljan answered on this page: loop carousel jquery
He uses a scrollTop loop for your problem.
I've also written a simple slider some time ago. I have now implemented the Roku C. Buljan method. Feel free to look at my code on Bitbucket.
https://bitbucket.org/d-stone/jqueryslider
An excerpt may help you:
value = prev_or_next == 'next' ? self.globals.slide_height : 0;
last = $('#container').find('> div:last');
first = $('#container').find('> div:first');
if(prev_or_next == 'prev') { // click on "next"-button
first.before(last); // put last element before first
settings.elements.inner.scrollTop(self.globals.slide_height); // set the scrollTop to 1 slide-height
}
// animation itself:
$('#container').stop().animate({scrollTop: value}, {
duration: settings.slide_speed,
done: function() {
if(prev_or_next == 'next') {
// put first item after last
last.after(first);
}
}
});
I'd advise you to validate your HTML (W3C Validator). There are some errors inside.
Invalid HTML can be the reason for some CSS and Javascript Errors.
I have a <div class="content toggle"> that I have hidden until a certain event is called, and then I add a class to it to show that it needs to be visible.
My current CSS looks like:
.content {
display: none;
}
.content.visible {
display: block;
}
My code for adding .visible looks like this:
[].forEach.call(document.getElementsByClassName('toggle'), function(x) {
x.classList.toggle('visible');
});
But, when the class .visible is added, the <div> is still display: none;. What's happening here? How can I fix it?
seems like your JS selects a class called "toggle" instead of "content":
getElementsByClassName('toggle')
There's 100 ways do what you want. Here's one solution.
<script>
function makeVisible() {
var myContentDiv = document.getElementById("mycontent");
myContentDiv.style.display = "block";
}
</script>
<div id="mycontent" class="content"></div>
<a id="mybutton" href="javascript:makeVisible()"></a>
Updated answer, to reflect the jsfiddle.
HTML:
<div class="content">hi</div>
<button id='button'>toggle visible</button>
JS
var button = document.getElementById('button');
button.onclick = function() {
var div = document.getElementById('content');
if (div.style.display !== 'none') {
div.style.display = 'none';
}
else {
div.style.display = 'block';
}
};
.content {
display: none;
}
.visible {
display: block;
}
?
Keep your display classes separate from your core class.
in jQuery:
$(this).toggleClass("visible hidden");
and the css:
<style>
.visible {
display: block;
}
.hidden {
display: none;
}
</style>
This is my JSFiddle
As you can see from the fiddle that there is a list that is being scrolled with the help of arrows.. So what I want is to animate that transition when the list visible and hidden.
I don't know about the animation. I have seen many examples and tried to adjust them with my example but it's not working... How do I get the list to animate?
$(document).ready(function(){
var code='';
for(var i=1;i<=20;i++)
{
code+="<li>list Item "+i+"</li>";
}
$('#list-items').html(code);
});
var list_items = [];
var index = 0;
var list_length = 0;
function getAllListItems() {
var temp = document.getElementsByTagName('li');
for (i = 0; i < temp.length; i++) {
list_items.push(temp[i]);
}
list_length = temp.length;
}
getAllListItems();
function move(dir) {
if (dir == left) {
list_items[index].style.display = 'block';
index--;
if (index < 0) {
index = 0;
}
} else if (dir == right) {
list_items[index].style.display = 'none';
if (index >= ((list_length) - 1)) {
index = (list_length) - 1;
} else {
index++;
}
} else {}
}
* {
box-sizing: border-box;
}
ul {
float:left;
height:50px;
width: 600px;
overflow: hidden;
}
ul li {
text-align: center;
border: 2px solid black;
width: 100px;
height: 50px;
float: left;
list-style-type: none;
background-color: aquamarine;
}
ul li:first-child {
display: block;
}
#left, #right {
float:left;
height:50px;
background-color:aqua;
font-size:2em;
padding-left: 20px;
padding-right:20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body onload='getAllListItems()'>
<div id='t'></div>
<button id='left' onClick="move(left)">
<</button>
<ul id='list-items'>
</ul>
<button id='right' onClick='move(right)'>></button>
</body>
You can easily just replace your lines:
list_items[index].style.display = 'block';
list_items[index].style.display = 'none';
with the jQuery show() and hide() functions:
$(list_items[index]).show("slow");
$(list_items[index]).hide("slow");
As demonstrated in my updated version of your Fiddle
For different transitions, you can use the animate() function, which lets you tell it what css properties to affect. In addition to numeric values, jQuery also supports the special values 'show', 'hide', and 'toggle' (which, incidentally, will show, hide, or toggle the show/hide status of an element using that property). So for instance, if you wanted to shrink them only horizontally and leave the vertical alone, you could change the .show() and .hide() calls to:
$(list_items[index]).animate({width:'show'}, 600);
$(list_items[index]).animate({width:'hide'}, 600);
I've demonstrated this in another updated Fiddle