Changing simultaneously text and image on slider - javascript

I made a slider with a series of images. I created two buttons (prev and next) that allow browsing the images.
I created also two divs where I put the slide's number and title.
My goal is to change the image, number, and title of the slide simultaneously each time a click event on prev or next buttons occurs.
I have started programming some months ago and I am having difficulties associating images with corresponding titles and numbers.
Could someone help me complete my code?
Actually, the following code works for me to show the image on click but is not complete.
I would like to change all the elements (image, title and number) at the same time after click.
More details on the picture:Screen of the homepage
// Carousel
let sliderImage = document.querySelector(".sliderImage");
let images = [
"carousel1.jpg",
"carousel2.jpg",
"carousel3.jpg",
"carousel4.jpg",
"carousel5.jpg",
"carousel6.jpg",
"carousel7.jpg",
];
let i = 0; // Current image index
// I have already created in html file 2 btns with "onclick" event
// that trigger the following functions:
function prev() {
if (i <= 0) i = images.length;
i--;
return getSlideImg();
}
function next() {
if (i >= images.length - 1) i = -1;
i++;
return getSlideImg();
}
function getSlideImg() {
return sliderImage.setAttribute("src", "img/" + images[i]);
}
<!-- Carousel -->
<div class="carousel-container">
<div class="carousel-slide">
<img src="./img/carousel1.jpg" alt="" class="sliderImage"/>
<!-- Carousel card -->
<div class="carousel__card-container">
<div class="carousel__card-title">Soggiorno</div>
<div class="carousel__slide-data">
<div class="slide__number">01</div>
<div class="slide__loader">
<div class="loader__line-grey">
<div class="loader__line-white"></div>
</div>
</div>
</div>
</div>
<!-- Carousel buttons -->
<div class="carousel-btn">
<a href="#" class="button left-arrow bottone" id="prevBtn" onclick="prev()">
<i class="ri-arrow-left-s-line btn-icon-small"></i>
</a>
<a href="#" class="button right-arrow bottone" id="nextBtn" onclick="next()">
<i class="ri-arrow-right-s-line btn-icon-small"></i>
</a>
</div>
</div>
</div>

set all values inside getSlideImg function so everything will update with corresponding image
// Carousel
let sliderImage = document.querySelector(".sliderImage"),
container = document.querySelector(".carousel-container")
let images = [
"carousel1.jpg",
"carousel2.jpg",
"carousel3.jpg",
"carousel4.jpg",
"carousel5.jpg",
"carousel6.jpg",
"carousel7.jpg",
];
let i = 0; // Current image index
// I have already created in html file 2 btns with "onclick" event
// that trigger the following functions:
function prev() {
if (i <= 0) i = images.length;
i--;
return getSlideImg();
}
function next() {
if (i >= images.length - 1) i = -1;
i++;
return getSlideImg();
}
function getSlideImg() {
container.querySelector(".slide__number").innerText = i + 1
container.querySelector(".carousel__card-title").innerText = images[i]
return sliderImage.setAttribute("src", "img/" + images[i]);
}
// for onload
getSlideImg()
<!-- Carousel -->
<div class="carousel-container">
<div class="carousel-slide">
<img src="./img/carousel1.jpg" alt="" class="sliderImage"/>
<!-- Carousel card -->
<div class="carousel__card-container">
<div class="carousel__card-title">Soggiorno</div>
<div class="carousel__slide-data">
<div class="slide__number">01</div>
<div class="slide__loader">
<div class="loader__line-grey">
<div class="loader__line-white"></div>
</div>
</div>
</div>
</div>
<!-- Carousel buttons -->
<div class="carousel-btn">
<a href="#" class="button left-arrow bottone" id="prevBtn" onclick="prev()">
<i class="ri-arrow-left-s-line btn-icon-small">prev</i>
</a>
<a href="#" class="button right-arrow bottone" id="nextBtn" onclick="next()">
<i class="ri-arrow-right-s-line btn-icon-small">next</i>
</a>
</div>
</div>
</div>

Related

I want circles to change color whenever one of them are clicked & have a Stop and Start function together

var check = null;
function Timer() {
if (check == null) {
var count = 10;
check = setInterval(function () {
count -= 1;
document.getElementById("VR").textContent = count;
if (count <= 0) clearInterval(check);
}, 1000);
}
}
function stop() {
clearInterval(check);
check = null;
document.getElementById("VR").textContent = "0";
}
<div class="VRcircle">
<div class="text">
<h1 id="VR">VR</h1>
</div>
</div>
<div class="circle circle1" onclick="Timer()">
<div class="text">
<a href="#">
<p>Scene</p>
<span>I</span>
</a>
</div>
</div>
<div class="circle circle2" onclick="Timer()">
<div class="text">
<a href="#">
<p>Scene</p>
<span>II</span>
</a>
</div>
</div>
<div class="circle circle3" onclick="stop()">
<div class="text">
<a href="#">
<p>Scene</p>
<span>III</span>
</a>
</div>
</div>
Circle1, circle2 & circle3 should change color whenever they are clicked and timer should be displayed on VR circle.
Would it be possible to start timer when i click on element and on second click stop it while it's running?
Could i click different elements without refreshing the page and how ?
Thanks in advance
I can display Timer() function on VR circle, i also have written stop() function, both of them works.
but can't do other things. my mind went blank probably.
Hope anyone will help me.

remove.EventListener() is changing how the program works

I am trying to do a div that appears when I click in one div and then disappear when I click out of it, I used a EventListener() to do it and the progrmam works fine without the removeEventListener(), but I need the to remove the EventListener() so the div can disappear when I click in the same div that makes it show.
When I use the removeEventListener() the event.target changes
On the code: [object HTMLBodyElement]
Off the code: [object HTMLDivElement]
Here is my code:
HTML:
<div class="account-settings gear m-r-120">
<!-- ACCOUNT SETTINGS -->
<span class="gear" onclick="settings()">
<i class="fas fa-cog fa-2x gear"></i>
<i class="fas fa-chevron-down gear m-t-7 p-l-5"></i>
</span>
</div>
<!-- ACCOUNT SETTINGS -->
<div class="settings-box trigger" id="settings-box" style="display: none">
<!-- SETTINGS BOX -->
<div class="change-box trigger">
Change Name
</div>
<div class="change-box trigger">
Change Password
</div>
<div class="change-box trigger">
Change Email
</div>
</div>
<!-- SETTINGS BOX -->
JS:
function settings() {
var box = document.getElementById("settings-box");
if (box.style.display === "none") {
document.addEventListener("click", setBox);
function setBox() {
let elements = document.getElementsByClassName("trigger");
let gear = document.getElementsByClassName("gear");
var click = false;
for (let i = 0; i < elements.length; i++) {
if (elements[i] === event.target) {
click = true;
}
}
if (!click) {
for (let j = 0; j < elements.length; j++) {
if (gear[j] === event.target) {
click = true;
}
}
}
if (click === false) {
box.style.display = "none";
this.removeEventListener("click", setBox);
} else {
box.style.display = "block";
}
}
} else {
box.style.display = "none";
}
}
Thank you in advance
UPDATE - Click outside div to hide div in pure JavaScript - question about the same problem, take a look.
Looks like you're using removeEventListener() wrong. You need to remove the listener only when you don't need to trigger your div visibility anymore. You can simplify your logic, just change the display of #settings-box when you click on the .gear span, without any addEventListener, because you use onclick handler. To show\hide div, I suggest using data attribute - docs
Should be something like this:
HTML
<div class="account-settings gear m-r-120">
<span class="gear" onclick="settings()">
<i class="fas fa-cog fa-2x gear"></i>
<i class="fas fa-chevron-down gear m-t-7 p-l-5"></i>
</span>
</div>
<!-- Add data attribute here!! --!>
<div
data-hidden="true"
class="settings-box trigger"
id="settings-box"
style="display: none;"
>
<div class="change-box trigger">
<a href="#" class="trigger">
Change Name
</a>
</div>
<div class="change-box trigger">
<a href="#" class="trigger">
Change Password
</a>
</div>
<div class="change-box trigger">
<a href="#" class="trigger">
Change Email
</a>
</div>
</div>
As you see, I add a data-hidden attribute, we will use it to track the visibility of the div.
JS:
function settings(){
var box = document.getElementById("settings-box");
// Gets hidden attribute.
var isHIdden = box.dataset.hidden;
if (!isHidden) {
// if hidden attribute is missing then
// we hide div and add hidden attribute.
box.style.display = "none";
box.dataset.hidden = "true";
} else {
// If hidden attribute is set then we show div
// and remove hidden attribute.
box.style.display = "block";
box.removeAttribute("hidden");
}
}
Let me know if it works for you.

How to get children of a div

User can, by pressing a button, select a particular topic of interest. When that happens, various divs will either become visible or invisible depending on whether that div has a link referring to that topic.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
var topics = [];
for (j = 0; j < children.length; j++) {
topics.push(children[j].getAttribute("asp-route-name"));
document.getElementById("firstTest").innerHTML = children[j].toString();
}
var b = topics.includes(topic);
if (b == true) {
var parentId = document.getElementById(topicAreas[i]).parentNode.id;
document.getElementById(parent).style.display = 'block';
} else {
document.getElementById(parent).style.display = 'none';
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
The trouble, as far as I can tell, begin early in the JS part. I can see that when a do var children=topicAreas[i].children, I get nothing.
I hope this is what you're trying to do. Based on what button you click, respective div is displayed.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
for (j = 0; j < children.length; j++) {
var parentId = topicAreas[i].parentNode.id;
if(children[j].getAttribute("asp-route-name") === topic){
document.getElementById(parentId).style.display = 'block';
}else{
document.getElementById(parentId).style.display = 'none';
}
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
Children isn't the issue. When you run your code you get the error "Uncaught TypeError: Cannot set property 'innerHTML' of null". Looking at your code where you are using .innerHTML, we see that you are trying to reference an element that you don't have in this code:
document.getElementById("firstTest")
Now, after adding that, you still have some items that you should change.
asp-action and asp-route-name are invalid HTML. Are you using a
framework that requires this syntax?
Don't use .getElementsByClassName().
Use .querySelectorAll() and Array.forEach() on the result for
easier looping.
Don't use .innerHTML when you aren't working with HTML strings as there are security and performance implications to doing so.
Avoid inline styles when you can. Using them causes duplication of code and code is harder to scale. Instead, use CSS classes and the .classList API.
It's not super clear exactly what is supposed to happen when clicking your buttons, but see the updated code below:
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
// Don't use .getElementsByClassName() as it provides a live node list
// and causes quite a performance hit, especially when used in loops.
// Use .querySelectorAll() and then use .forEach() on the collection that
// it returns to iterate over them.
area.querySelectorAll(".topicArea").forEach(function(area){
var topics = [];
// No need for children, here. Again, use .querySelectorAll()
area.querySelectorAll("*").forEach(function(child) {
topics.push(child.getAttribute("asp-route-name"));
document.getElementById("firstTest").textContent = child.getAttribute("asp-route-name");
});
if (topics.indexOf(topic) > -1) {
// Don't use inline styles if you can avoid it.
// Instead use pre-made classes.
area.classList.add("hidden");
}
else {
area.classList.remove("hidden");
}
});
}
/* Use CSS classes when possible instead of inline styles */
.hidden { display:none; }
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
<div id="firstTest"></div>

set class active to next slide element

I have a question about Javascript.
You can find my HTML markup below
<div class="slides">
<div class="slide active" id="one"></div>
<div class="slide" id="two"></div>
<div class="slide" id="third"></div>
<div class="slide" id="fourth"></div>
</div>
<button onclick="slide-down()">
Next slide
</button>
<button onclick="slide-up()">
Previous slide
</button>
What can i do if the user click on the button slide-down to remove with pure javascript the class 'active' en set this to the next slide element?
You can use a single function, set class at <button> elements to "prev" and "next", pass clicked button .className to function; .getElementsByClassName(), .nextElementSibling, .previousElementSibling
.active {
color: green;
}
<div class="slides">
<div class="slide active" id="one">one</div>
<div class="slide" id="two">two</div>
<div class="slide" id="third">third</div>
<div class="slide" id="fourth">fourth</div>
</div>
<button class="next" onclick="slide(this.className)">
Next slide
</button>
<button class="prev" onclick="slide(this.className)">
Previous slide
</button>
<script>
var active = document.getElementsByClassName("active");
function slide(prevNext) {
if (prevNext === "next") {
if (active[0].nextElementSibling) {
active[0].nextElementSibling.className = "active";
active[0].className = "";
}
} else {
if (active[0].previousElementSibling) {
active[0].previousElementSibling.className = "active";
active[active.length - 1].className = "";
}
}
}
</script>
Something like the below will work. Makes use of many javascript DOM properties and methods. You will need to change the names of your functions slightly as a hyphen is not valid in a name of a function. Ive replaced with underscores.
function slide_down(){
var elems = document.querySelectorAll(".slide");
var curr = document.querySelector(".active");
curr.classList.remove("active");
if(curr.nextElementSibling)
curr.nextElementSibling.classList.add("active");
else
elems[0].classList.add("active");
}
function slide_up(){
var elems = document.querySelectorAll(".slide");
var curr = document.querySelector(".active");
curr.classList.remove("active");
if(curr.previousElementSibling)
curr.previousElementSibling.classList.add("active");
else
elems[elems.length-1].classList.add("active");
}
.active{background-color:red}
<div class="slides">
<div class="slide active" id="one">1</div>
<div class="slide" id="two">2</div>
<div class="slide" id="third">3</div>
<div class="slide" id="fourth">4</div>
</div>
<button onclick="slide_down()">
Next slide
</button>
<button onclick="slide_up()">
Previous slide
</button>
Here is an example I wrote. Jasmiec answered before I finished, and I honestly like some of the different methods used in that example. As already mentioned, you will need to change the names of your functions because a hyphen makes the name invalid.
<div class="slides">
<div class="slide active" id="one"></div>
<div class="slide" id="two"></div>
<div class="slide" id="three"></div>
<div class="slide" id="four"></div>
</div>
<button onclick="slideDown()">
Next slide
</button>
<button onclick="slideUp()">
Previous slide
</button>
<script>
var slides = ["one", "two", "three", "four"]
function slideDown() {
var element = document.getElementsByClassName('active')[0];
var index = slides.indexOf(element.id) + 1;
if (index < slides.length) {
element.className = "slide";
document.getElementById(slides[index]).className = "slide active";
}
}
function slideUp() {
var element = document.getElementsByClassName('active')[0];
var index = slides.indexOf(element.id) - 1;
if (index >= 0) {
element.className = "slide";
document.getElementById(slides[index]).className = "slide active";
}
}
</script>

Accordion with javascript

I've been trying to get an accordion movement going with javascript.
The problem that I'm having is having one close if it's already open and stay closed.
Right now the according closing one and opening another when I click a different div.
I see that the argument is always resolving to true because I'm removing the classes.. but I can't seem to find a away to get around that so I could have a nice accordion.
<div class="speaker-container">
<div class="span3 offset1 speaker" id="sp-info-0">
<div class="speaker-img">
<div class="hover"></div>
<img src="" alt="">
</div>
<h4>Title</h4>
</div>
<div class="speaker-info" id="sp-info-0">
<button class="close-speaker">Close</button>
<h2>Title</h2>
</div>
<div class="span3 offset1 speaker" id="sp-info-1">
<div class="speaker-img">
<div class="hover"></div>
<img src="" alt="">
</div>
<h4>Sub Title</h4>
</div>
<div class="speaker-info" id="sp-info-1">
<button class="close-speaker">Close</button>
<h2>Title</h2>
</div>
<div class="span3 offset1 speaker" id="sp-info-2">
<div class="speaker-img">
<div class="hover"></div>
<img src="" alt="">
</div>
<h4>Title</h4>
</div>
<div class="speaker-info" id="sp-info-2">
<button class="close-speaker">Close</button>
<h2>Title</h2>
</div>
</div>
var timer;
$('.speaker-container .speaker').on('click', function(){
var speakerContainer = document.getElementsByClassName('speaker-container');
var self = this;
var children = $('.speaker-container').children();
var selfHeight = this.clientHeight;
var parentOffset = this.parentElement.offsetHeight;
var selfOffset = this.nextElementSibling.offsetHeight;
console.dir(children);
console.log(parentOffset);
$('.speaker-container').removeClass('open').css({'height' : selfHeight + 'px'});
for (var i = 0; i < children.length; i++) {
if (children[i].className == 'speaker-info fade') {
console.dir(children[i]);
$(children[i]).removeClass('fade');
}
}
if (self.parentElement.className !== 'speaker-container open' && self.nextElementSibling.className !== 'speaker-info fade') {
timer = setTimeout(function(){
self.parentElement.setAttribute('class' , 'speaker-container open');
self.parentElement.style.height = selfOffset + selfHeight + 'px';
self.nextElementSibling.style.top = selfHeight + 'px';
self.nextElementSibling.setAttribute('class' , 'speaker-info fade');
// return false;
}, 500);
} else {
$('.speaker-container').removeClass('open').css({'height' : selfHeight + 'px'});
self.nextElementSibling.setAttribute('class' , 'speaker-info');
window.clearTimeout(timer);
}
});
Make a class that has the item open. (let's say the class is "open")
Make a class that has the item closed. (let's say the class is closed")
let's say all the accordion items are in the accordion class.
function that opens an item:
cycle through and remove any existing open item classes, add closed class.
add open class to the selected item.
by default, give closed class to all items (except the one you want open by default, if any)
with javascript it would look something like:
function openOnClick()
{
var openaccordion=document.getElementsByClassName('open');
openaccordion.className.replace( /(?:^|\s)open(?!\S)/g , 'close' );
this.className.replace( /(?:^|\s)close(?!\S)/g , 'open' );
}
with jQuery it would look like this:
$('div.accordion').click(function(){
$('.open').removeClass('open').addClass('close');
$(this).removeClass('close').addClass('open');
}
you can use jqueryui to get some sliding effects in there pretty simply too:
$(this).switchClass('close','open',1000);

Categories

Resources