This is my code so far:
const mediaInViewport = document.querySelectorAll('.media');
const links = Array.from(document.querySelectorAll('.link'));
let actLink = links[0];
document.body.addEventListener('click', (event) => {
if (event.target.tagName === 'a') {
actLink.classList.remove('active');
actLink = links.find(link => event.target.href === link.href)
actLink.classList.add('active');
}
}, false)
observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.target && entry.isIntersecting) {
const closestParent = entry.target.closest('section');
if (closestParent) {
actLink.classList.remove('active');
actLink = links.find(link =>
link.href.slice(link.href.lastIndexOf('#')) === `#${closestParent.id}`
)
actLink.classList.add('active');
}
}
});
}, {
threshold: 0
});
window.addEventListener('DOMContentLoaded', () => {
setTimeout( // Wait for images to fully load
() => {
mediaInViewport.forEach((item) => {
observer.observe(item);
});
}, 1000);
});
* {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 30px;
text-decoration: none;
color: inherit;
}
body {
display: flex;
cursor: default;
}
#left,
#right {
width: 50%;
height: 100vh;
overflow-y: scroll;
scroll-behavior: smooth;
}
#left {
background-color: rgb(220, 220, 220);
}
#right {
background-color: rgb(200, 200, 200);
}
.media {
padding: 10px;
padding-bottom: 0;
}
.media:nth-last-child(1) {
margin-bottom: 10px;
}
img {
display: block;
width: 100%;
}
.link {
cursor: pointer;
}
.active {
background-color: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="left">
<a class="link active" href="#landscape">Landscapes</a>
<a class="link" href="#cats">Cats</a>
<a class="link" href="#beer">Beer</a>
<a class="link" href="#food">Food</a>
</div>
<div id="right">
<section id="landscape">
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
</section>
<section id="cats">
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
</section>
<section id="beer">
<article class="media beer">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
</article>
</section>
<section id="food">
<article class="media food">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
</article>
</section>
</div>
The observation function should work with all window sizes. Currently, if the window size is a bit higher, for example the "Beer" link doesn't receive the .active class if you click on it or scroll too insensitive.
Is there a way to fix that?
Rules like the following would be needed:
Always only the last observed object should trigger an .active
class.
But: If there are at one point different observable objects visible
(for example after a click on the link "Beer"), then the "most
dominant" one (the one that is not cut off and most present) should
trigger the .active class.
I would be sooooo thankful for help! <3
const mediaInViewport = Array.from(document.querySelectorAll('.media'));
const sections = Array.from(document.querySelector('#right').children);
const links = Array.from(document.querySelectorAll('.link'));
let actLink = links[0];
let actSection = null;
let targetLink = null;
let targetSection = null;
document.body.addEventListener('click', (event) => {
if (event.target.tagName === 'A') {
event.preventDefault();
targetLink = event.target;
targetSection = sections.find(section => section.id === targetLink.href.slice(targetLink.href.lastIndexOf('#')+1))
location.hash = targetLink.href.slice(targetLink.href.lastIndexOf('#'));
actLink.classList.remove('active');
actLink = links.find(l => event.target.href === l.href)
actLink.classList.add('active');
}
}, false)
observer = new IntersectionObserver((entries, observer) => {
entries.forEach((entry) => {
if (entry.target && entry.isIntersecting) {
const closestParent = entry.target.closest('section');
if (closestParent) {
actLink.classList.remove('active');
if (!targetLink) {
actLink = links.find(link =>
link.href.slice(link.href.lastIndexOf('#')) === `#${closestParent.id}`
)
} else {
if (closestParent === targetSection){
targetLink = null
}
}
actSection = sections.find(section => section.id === actLink.href.slice(actLink.href.lastIndexOf('#')))
actLink.classList.add('active');
}
}
});
}, {
threshold: 0.3
});
window.addEventListener('DOMContentLoaded', () => {
setTimeout( // Wait for images to fully load
() => {
mediaInViewport.forEach((item) => {
observer.observe(item);
});
}, 1000);
});
* {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 30px;
}
body {
display: flex;
cursor: default;
}
#left,
#right {
width: 50%;
height: 100vh;
overflow-y: scroll;
scroll-behavior: smooth;
}
#left {
background-color: rgb(220, 220, 220);
}
#right {
background-color: rgb(200, 200, 200);
}
.media {
padding: 10px;
padding-bottom: 0;
}
.media:nth-last-child(1) {
margin-bottom: 10px;
}
img {
display: block;
width: 100%;
}
.link:active {
cursor: pointer;
}
a:target {
background-color: black;
color: white;
}
a {
text-decoration: none;
color: inherit;
}
section:target {
background-color: black;
color: white;
}
.active {
background-color: black;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="left">
<a class="link active" href="#landscape">Landscapes</a>
<a class="link" href="#cats">Cats</a>
<a class="link" href="#beer">Beer</a>
<a class="link" href="#food">Food</a>
</div>
<div id="right">
<section id="landscape">
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
<div class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/8d/Freudenberg_sg_Switzerland.jpg">
</div>
</section>
<section id="cats">
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
<article class="media">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b8/Cute_cat_%281698598876%29.jpg">
</article>
</section>
<section id="beer">
<article class="media beer">
<img src="https://upload.wikimedia.org/wikipedia/commons/8/89/Craft_Beer_at_the_Taedonggang_Microbrewery_No._3_%2812329931855%29.jpg">
</article>
</section>
<section id="food">
<article class="media food">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Good_Food_Display_-_NCI_Visuals_Online.jpg/1200px-Good_Food_Display_-_NCI_Visuals_Online.jpg">
</article>
</section>
</div>
Related
There are 3 container classes
Two exit buttons are viewable inside each of their respective containers, where they each take you to a different container when clicked on.
<div class="container1"></div>
<div class="container2 hide"></div>
<div class="container3 hide"></div>
Code I am working on.
How would it be written differently to make it better?
How can this be improved?
https://jsfiddle.net/an23j14r/
function exitClickHandler(e) {
if (e.target.classList.contains("exit")) {
document.querySelector(".container2").classList.add("hide");
document.querySelector(".container3").classList.add("hide");
document.querySelector(".container1").classList.remove("hide");
console.log('Page1');
}
if (e.target.classList.contains("exitPage2")) {
document.querySelector(".container1").classList.add("hide");
document.querySelector(".container3").classList.add("hide");
document.querySelector(".container2").classList.remove("hide");
console.log('Page2');
}
if (e.target.classList.contains("exitPage3")) {
document.querySelector(".container2").classList.add("hide");
document.querySelector(".container1").classList.add("hide");
document.querySelector(".container3").classList.remove("hide");
console.log('Page3');
}
window.scrollTo(0, 0);
}
Here are the exit buttons that go to their corresponding CSS classes that they go to in the code.
You would click on a button and it should take you to a specific CSS class/page that it goes to.
There are 3 container classes, when 1 of 2 buttons is clicked on, 2 container classes should be hidden, where 1 of them becomes visible.
<div class="container1">
<button class="exit exitpPage2" type="button"></button>
<button class="exit exitpPage3" type="button"></button>
</div>
<div class="container2 hide">
<button class="exit" type="button"></button>
<button class="exit exitpPage3" type="button"></button>
</div>
<div class="container3 hide">
<button class="exit" type="button"></button>
<button class="exit exitpPage2" type="button"></button></div>
Each container/page would be unhidden when a button is clicked on, where the other containers/pages would stay hidden.
When exit button attached to .container1 is clicked on, .container2 and .container3 should be hidden.
When exit button attached to .container2 is clicked on, .container1 and .container3 should be hidden.
When exit button attached to .container3 is clicked on, .container2 and .container1 should be hidden.
Here is my code example:
const manageCover = (function makeManageCover() {
function showCover(playButton) {
const cover = playButton.parentElement;
cover.classList.add("active");
}
function openCurtain(curtain) {
curtain.classList.add("slide");
}
function coverClickHandler(evt) {
const cover = evt.currentTarget;
showCover(cover);
const curtain = evt.currentTarget.parentElement.parentElement.parentElement;
openCurtain(curtain);
}
function addCoverHandler(coverSelector, handler) {
const cover = document.querySelector(coverSelector);
cover.addEventListener("click", handler);
}
function addClickToButtons(playButtons) {
playButtons.forEach(function playButtonHandler(playButton) {
playButton.addEventListener("click", coverClickHandler);
});
}
function init( /*selectors*/ ) {
//config.containers = document.querySelector(selectors.container);
// const allContainers = document.querySelector(".container");
//const playButtons = document.querySelector(selectors.playButton);
const allPlaybuttons = document.querySelectorAll(".cover");
//const allPlaybuttons = document.querySelectorAll(".embed-youtube-play");
addClickToButtons(allPlaybuttons);
}
return {
addCoverHandler,
init
};
}());
const manageUI = (function makeManageUI() {
document.body.scrollTop = 0;
const players = [];
function findPlayers() {
const allCovers = document.querySelectorAll(".cover");
const allWrappers = document.querySelectorAll(".wrap");
allCovers.forEach(function addToPlayers(cover, index) {
players.push({
"cover": cover,
"wrapper": allWrappers[index]
});
});
}
function getWrapper(cover) {
const index = players.findIndex(
(player) => player.cover === cover
);
return players[index].wrapper;
}
function exitClickHandler(e) {
if (e.target.classList.contains("exit")) {
document.querySelector(".container2").classList.add("hide");
document.querySelector(".container3").classList.add("hide");
document.querySelector(".container1").classList.remove("hide");
console.log('Page1');
}
if (e.target.classList.contains("exitPage2")) {
document.querySelector(".container1").classList.add("hide");
document.querySelector(".container3").classList.add("hide");
document.querySelector(".container2").classList.remove("hide");
console.log('Page2');
}
if (e.target.classList.contains("exitPage3")) {
document.querySelector(".container2").classList.add("hide");
document.querySelector(".container1").classList.add("hide");
document.querySelector(".container3").classList.remove("hide");
console.log('Page3');
}
window.scrollTo(0, 0);
}
function addClickToExit(exitButtons) {
exitButtons.forEach(function addExitButtonHandler(exitButtons) {
exitButtons.addEventListener("click", exitClickHandler);
});
}
function addExitHandlers(callback) {
const resetVideo = document.querySelectorAll(".exit");
resetVideo.forEach(function resetVideoHandler(video) {
video.addEventListener("click", callback);
});
}
function init() {
findPlayers();
const exitButtons = document.querySelectorAll(".exit");
addClickToExit(exitButtons);
}
return {
addExitHandlers,
getWrapper,
init
};
}());
const videoPlayer = (function makeVideoPlayer() {
let player;
const tag = document.createElement("script");
tag.src = "https://www.youtube.com/player_api";
const firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onPlayerReady(event) {
player = event.target;
player.setVolume(100);
}
function onPlayerStateChange(event) {
const player = event.target;
return player;
}
function addPlayer(video, playerOptions) {
playerOptions.videoId = playerOptions.videoId || video.dataset.id;
playerOptions.events = playerOptions.events || {};
playerOptions.events.onReady = onPlayerReady;
playerOptions.events.onStateChange = onPlayerStateChange;
const player = new YT.Player(video, playerOptions);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const playerVars = {
autoplay: 1,
controls: 1,
disablekb: 1,
fs: 0,
iv_load_policy: 3
};
const defaults = {
height: 360,
host: "https://www.youtube-nocookie.com",
playerVars,
width: 640
};
function show(el) {
el.classList.remove("hide");
}
function combinePlayerOptions(opts1 = {}, opts2 = {}) {
const combined = Object.assign({}, opts1, opts2);
Object.keys(opts1).forEach(function checkObjects(prop) {
if (typeof opts1[prop] === "object") {
combined[prop] = Object.assign({}, opts1[prop], opts2[prop]);
}
});
return combined;
}
function createPlayer(videoWrapper, playerOptions = {}) {
const video = videoWrapper.querySelector(".video");
const options = combinePlayerOptions(defaults, playerOptions);
return videoPlayer.addPlayer(video, options);
}
function playerAdder(wrapper, playerOptions) {
return function addPlayerCallback() {
initPlayer(wrapper, playerOptions);
};
}
function removePlayer(wrapper) {
wrapper.player.destroy();
delete wrapper.player;
console.log("removePlayer");
}
function removePlayerHandler(evt) {
const el = evt.target;
let container = el.closest(".container");
let wrappers;
if (container) { //if multiple players
wrappers = container.querySelectorAll(".remove .wrap");
} else { //if single player
container = el.closest(".remove");
wrappers = container.querySelectorAll(".wrap");
}
wrappers.forEach(function(wrapper) {
if (wrapper.player) {
removePlayer(wrapper);
}
});
}
function initPlayer(wrapper, playerOptions) {
show(wrapper);
const player = createPlayer(wrapper, playerOptions);
wrapper.player = player;
}
return {
adder: playerAdder,
removePlayerHandler
};
}());
const players = (function coverUIPlayerFacade() {
function addPlayer(coverSelector, playerOptions) {
const cover = document.querySelector(coverSelector);
const wrapper = manageUI.getWrapper(cover);
const callback = managePlayer.adder(wrapper, playerOptions);
manageCover.addCoverHandler(coverSelector, callback);
}
function init() {
manageCover.init({
playButton: ".cover"
});
manageUI.init({});
manageUI.addExitHandlers(managePlayer.removePlayerHandler);
}
return {
add: addPlayer,
init
};
}());
players.init();
function onYouTubeIframeAPIReady() {
players.add(".playa", {
playerVars: {
loop: 1,
playlist: "djV11Xbc914"
}
});
players.add(".playb", {});
players.add(".playc", {});
players.add(".playd", {});
players.add(".playe", {
playerVars: {
playlist: ["mnfmQe8Mv1g", "M7lc1UVf-VE",
"-Xgi_way56U", "CHahce95B1g"
]
}
});
players.add(".playf", {});
players.add(".playg", {});
players.add(".playh", {});
players.add(".playi", {});
players.add(".playj", {
playerVars: {
playlist: ["mnfmQe8Mv1g", "M7lc1UVf-VE",
"-Xgi_way56U", "CHahce95B1g"
]
}
});
players.add(".playk", {});
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #302b63;
}
.container2 .container {
background: teal;
}
.container3 .container {
background: green;
}
.container1 {
position: absolute;
left: 0;
right: 0;
min-height: 100%;
min-width: 255px;
display: flex;
padding: 8px 8px;
}
.curtain1 {
flex: 1 0 0;
margin: auto;
max-width: 640px;
border: 21px solid;
border-radius: 12px;
border-color: #000 #101010 #000 #101010;
position: relative;
}
.ratio-keeper {
position: relative;
height: 0;
padding-top: 56.25%;
margin: auto;
overflow: hidden;
}
.container {
position: absolute;
left: 0;
right: 0;
min-height: 100%;
padding: 8px 8px;
}
.curtain {
margin: auto auto 40px;
max-width: 640px;
border: 21px solid;
border-radius: 12px;
border-color: #000 #101010 #000 #101010;
position: relative;
}
.embed-youtube iframe,
.embed-youtube .embed-youtube-play,
.embed-youtube .embed-youtube-play::before {
position: absolute;
}
.embed-youtube iframe {
height: 100%;
width: 100%;
top: 0;
left: 0;
}
.embed-youtube .embed-youtube-play {
-webkit-appearance: none;
appearance: none;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
width: 90px;
height: 90px;
border-radius: 50%;
cursor: pointer;
border: 9px solid blue;
background: transparent;
filter: drop-shadow(3px 3px 3px #000000b3);
z-index: 1;
}
.embed-youtube-play::before {
content: "";
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 27px solid blue;
transform: translateX(4px);
}
.embed-youtube-play:hover {
box-shadow: 0 0 0 5px rgba(43, 179, 20, 0.5);
}
.embed-youtube-play:focus {
outline: 0;
box-shadow: 0 0 0 5px rgba(0, 255, 255, 0.5);
}
.embed-youtube.active .embed-youtube-play {
display: none;
}
#keyframes rotate {
0% {
transform: rotate(0deg);
}
99.9% {
border-color: red transparent red transparent;
pointer-events: none;
}
100% {
transform: rotate(360deg);
border-color: blue;
}
}
#keyframes triangle {
0% {
opacity: 0;
}
99.9% {
opacity: 0;
}
100% {
border-left-color: blue;
opacity: 1;
}
}
.exit {
position: absolute;
top: auto;
bottom: -47.63px;
margin: auto;
right: 0;
left: 0;
width: 47px;
height: 47px;
cursor: pointer;
border-radius: 100%;
background: transparent;
border: 5px solid red;
box-sizing: border-box;
clip-path: circle(50%);
}
.exit::before,
.exit::after {
content: "";
background-color: red;
width: 47px;
height: 5px;
position: absolute;
top: 0px;
left: -5px;
right: 0;
bottom: 0;
margin: auto;
}
.exit::before {
transform: rotate(45deg);
}
.exit::after {
transform: rotate(-45deg);
}
.exit.exitPage2 {
position: absolute;
top: auto;
bottom: -47.63px;
margin: auto;
right: 200px;
left: 0;
border: 5px solid blue;
}
.exit.exitPage2::before,
.exit.exitPage2::after {
background-color: blue;
}
.exit.exitPage3 {
position: absolute;
top: auto;
bottom: -47.63px;
margin: auto;
right: 0px;
left: 200px;
border: 5px solid purple;
}
.exit.exitPage3::before,
.exit.exitPage3::after {
background-color: purple;
}
.hide {
display: none;
}
<div class="container1">
<div class="curtain1 remove">
<div class="ratio-keeper">
<div class="video-one"></div>
<div class="wrap embed-youtube ">
<div class="video embed-youtube " data-id="djV11Xbc914">
</div>
<button class="playa cover embed-youtube-play" type="button"></button>
</div>
</div>
<button class="exit exitPage2" type="button"></button>
<button class="exit exitPage3" type="button"></button>
</div>
</div>
<div class="container2 hide">
<div class="container ">
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-two"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playb cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-three"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playc cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-four"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playd cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-five"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playe cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-six"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playf cover embed-youtube-play" type="button"></button>
</div>
</div>
<button class="exit" type="button"></button>
<button class="exit exitPage3" type="button"></button>
</div>
</div>
</div>
<div class="container3 hide">
<div class="container ">
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-seven"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playg cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-eight"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playh cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-nine"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playi cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-ten"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playj cover embed-youtube-play" type="button"></button>
</div>
</div>
</div>
<div class="curtain remove">
<div class="ratio-keeper">
<div class="video-eleven"></div>
<div class="wrap embed-youtube">
<div class="video embed-youtube" data-id="djV11Xbc914">
</div>
<button class="playk cover embed-youtube-play" type="button"></button>
</div>
</div>
<button class="exit" type="button"></button>
<button class="exit exitPage2" type="button"></button>
</div>
</div>
</div>
If you want something that is similar to a carousel, you only need two buttons outside each container to control the index of the container that should be visible. The index start at 0 and is then changed ±1 steps depending on which button that is clicked.
toggleContainer() checks that the index of the container isn't out of bounce (less than 0 or bigger than the number of containers).
hideAllContainersBut() loops through the container "array" and hides every container except the current index.
document.getElementById('prev-button').addEventListener('click', toggleContainers);
document.getElementById('next-button').addEventListener('click', toggleContainers);
let containers = document.querySelectorAll('.container')
var index = 0;
function toggleContainers(event) {
let indexChange = event.target.dataset.indexChange;
index = index + Number(indexChange);
if (index < 0) { index = containers.length - 1; };
if (index >= containers.length) { index = 0; };
hideAllContainersBut(index);
}
function hideAllContainersBut(index) {
for (let i = 0; i < containers.length; i++) {
containers[i].hidden = index !== i;
}
}
.container {
height: 15vw;
padding: 1rem;
margin-bottom: 1rem;
}
button {
cursor: pointer;
}
.container.one {
background-color: red;
}
.container.two {
background-color: lightgreen;
}
.container.three {
background-color: yellow;
}
<section>
<div class="container one">
Container 1
</div>
<div class="container two" hidden>
Container 2
</div>
<div class="container three" hidden>
Container 3
</div>
<button id="prev-button" data-index-change="-1" type="button">Previous</button>
<button id="next-button" data-index-change="1" type="button">Next</button>
</section>
I have an automatic sliding carousel which is working fine except that when it reach the last image then it just freeze on the last image instead of auto slide to the first image. I just can't remake my javascript code alone. Strange but autosliding to the first image was working a few months ago. I had nothing change to the code but seems after last updates of chrome its just not working correctly neither on pc neither on mobile devices. Here is my javascript code:
const carousels = document.querySelectorAll('.img-carousel');
const prevBtn = document.querySelectorAll('.prev');
const nextBtn = document.querySelectorAll('.next');
let carsouselImages = document.querySelectorAll('.img-carousel div');
//Next Carousel
carousels.forEach((carousel, index)=>{
const nextCarousel = () => {
if(carsouselImages[carsouselImages.length - 1]) {
carousel.scrollTo(0, 0);
}
carousel.scrollBy(300, 0);
};
nextBtn[index].addEventListener('click', e => {
nextCarousel();
});
//Prev Carousel
const prevCarousel = () => {
if(carsouselImages[0]) {
carousel.scrollTo(4800,0);
}
carousel.scrollBy(-300, 0);
};
prevBtn[index].addEventListener('click', e => {
prevCarousel();
});
// Auto carousel
const auto = true; // Auto scroll
const intervalTime = 5000;
let sliderInterval;
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
};
carousel.addEventListener('mouseover', (stopInterval) => {
clearInterval(sliderInterval);
});
carousel.addEventListener('mouseleave', (startInterval) => {
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
}
});
//for mobile events
carousel.addEventListener('touchstart', (stopIntervalT) => {
clearInterval(sliderInterval);
});
carousel.addEventListener('touchend', (startIntervalT) => {
if (auto) {
sliderInterval = setInterval(nextCarousel, intervalTime);
}
});
//Debounce
var previousCall;
window.addEventListener('resize', () => {
if (previousCall >= 0) {
clearTimeout(previousCall);
}
});
});
Here are css and html codes if needed:
/** img-carousel **/
#imgages-carousel {
display: grid;
align-items: center;
justify-items: center;
padding: 40px 0px;
}
#imgages-carousel1 {
display: grid;
align-items: center;
justify-items: center;
padding: 40px 0px;
}
.img-carousel-container {
width: 800px;
position: relative;
}
.img-carousel {
display: flex;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
padding-bottom: 5px;
}
.img-carousel div {
flex: none;
scroll-snap-align: start;
width: 800px;
position: relative;
}
.img-carousel div img {
display: block;
width: 100%;
object-fit: cover;
}
.img-carousel div p {
position: absolute;
top: 0;
right: 10px;
background: rgba(0,0,0,0.5);
color: #fff;
padding: 5px;
border-radius: 10px;
}
.img-carousel-container button {
position: absolute;
top: calc(50% - 15px);
transform: translateY(-50%);
border: none;
background-color: rgba(255, 193, 7, 0.7);
color: #000;
cursor: pointer;
padding: 10px 15px;
border-radius: 50%;
outline: none;
opacity: 0;
transition: all ease-in-out 0.5s;
}
.prev {
left: 10px;
}
.next {
right: 10px;
}
.img-carousel-container:hover button {
opacity: 1;
}
.img-carousel-container button:hover {
background-color: #ffc107;
}
/** custom scrollbar **/
.img-carousel::-webkit-scrollbar {
width: 10px;
height: 10px;
}
.img-carousel::-webkit-scrollbar-thumb {
background: #ffc107;
border-radius: 10px;
}
.img-carousel::-webkit-scrollbar-track {
background: transparent;
}
.img-carousel-container:hover .img-carousel::-webkit-scrollbar-thumb {
visibility: visible;
}
#media screen and (max-width: 800px) {
.img-carousel-container {
width: 100%;
}
.img-carousel div {
width: 100%;
}
}
html:
<!-- section images carousel -->
<section id="imgages-carousel">
<div class="img-carousel-container">
<div class="img-carousel">
<div>
<img src="https://source.unsplash.com/9Nok_iZEgLk/800x450">
<p>1/6</p>
</div>
<div>
<img src="https://source.unsplash.com/4v7ubW7jz1Q/800x450">
<p>2/6</p>
</div>
<div>
<img src="https://source.unsplash.com/rtCujH697DU/800x450">
<p>3/6</p>
</div>
<div>
<img src="https://source.unsplash.com/ELv8fvulR0g/800x450">
<p>4/6</p>
</div>
<div>
<img src="https://source.unsplash.com/LoPGu6By90k/800x450">
<p>5/6</p>
</div>
<div>
<img src="https://source.unsplash.com/Ndz3w6MCeWc/800x450">
<p>6/6</p>
</div>
</div>
<button class="prev"><i class="fas fa-chevron-left fa-2x"></i></button>
<button class="next"><i class="fas fa-chevron-right fa-2x"></i></button>
</div>
</section>
<section id="imgages-carousel1">
<div class="img-carousel-container">
<div class="img-carousel">
<div>
<img src="https://source.unsplash.com/9Nok_iZEgLk/800x450">
<p>1/6</p>
</div>
<div>
<img src="https://source.unsplash.com/4v7ubW7jz1Q/800x450">
<p>2/6</p>
</div>
<div>
<img src="https://source.unsplash.com/rtCujH697DU/800x450">
<p>3/6</p>
</div>
<div>
<img src="https://source.unsplash.com/ELv8fvulR0g/800x450">
<p>4/6</p>
</div>
<div>
<img src="https://source.unsplash.com/LoPGu6By90k/800x450">
<p>5/6</p>
</div>
<div>
<img src="https://source.unsplash.com/Ndz3w6MCeWc/800x450">
<p>6/6</p>
</div>
</div>
<button class="prev"><i class="fas fa-chevron-left fa-2x "></i></button>
<button class="next"><i class="fas fa-chevron-right fa-2x "></i></button>
</div>
</section>
I need the country tab to remain, when the sites expends. I think a forEach loop is causing issues and I am not sure how to adress this, any help is greatly appreciated. I have data to display for over 50 countries and once the function works, my "country" tab will be Copy/pasted, I thought of using hard coded ID but its gonna take forever :(
HTML
<li class="country"><div class="list_container">
<button class="country_name">Algeria</button>
<ul class="site_list">
<div class="site_container">
<li class="site">Bejaja</li>
<img src="imgs/Algeria.jpg" alt="">
</div>
<div class="site_container">
<li class="site">Constantine</li>
<img src="imgs/Algeria.jpg" alt="">
</div>
<div class="site_container">
<li class="site">Jijel</li>
<img src="imgs/Algeria.jpg" alt="">
</div>
<div class="site_container">
<li class="site">Setif</li>
<img src="imgs/Algeria.jpg" alt="">
</div>
</ul>
</div>
</li>
JS
const country = document.querySelectorAll('.list_container');
// country selection
country.forEach((item) => {
const btn = item.querySelector('.country_name');
btn.addEventListener('click', () => {
country.forEach((site) => {
if(site !== item) {
site.classList.remove('show_sites')
}
})
item.classList.toggle('show_sites')
})
})
// site selection
const siteGroup = document.querySelectorAll('.site_container');
siteGroup.forEach((item) => {
console.log(item);
siteBtn = item.querySelector('.site_link');
console.log(siteBtn)
siteBtn.addEventListener('click', () => {
siteGroup.forEach(site => {
console.log(site)
if(site !== item) {
site.classList.remove('display_site')
}
})
item.classList.toggle('display_site')
})
})```
CSS
.country_list {
height: 100%;
width: 100%;
margin: 0;
padding: 1em;
}
.country {
list-style-type: none;
padding: 0em;
margin: 0.5em;
}
.country_name {
text-decoration:none;
background-color: rgba(114, 114,114, 0.5);
padding: 0.3em 1em;
color: white;
border-radius: 15px;
z-index: 3;
position: relative;
}
.list_container {
height: 2em;
width: 80%;;
overflow: hidden;
}
.site_list {
list-style-type: none;
background-color: rgba(255,255,255, 0.5);
border-radius: 5px;
width: 50em;
z-index: 4;
padding: 0.3em;
overflow: hidden;
}
.site_container {
height: 1.3em;
overflow: hidden;
}
.display_site {
height: 3.5em;
}
.site {
padding: 0.2em;
}
.show_sites {
height: 30em;
}
I have some divs generated dynamically. Once all the divs are selected submit button has to be enabled, can someone please help me?
let card = document.getElementsByClassName('card');
let allSelected = document.querySelectorAll('selected');
let btn = document.getElementsByClassName('btn');
for (var i = 0; i < card.length; i++) {
card[i].addEventListener('click', function(e) {
e.target.classList.add('selected');
})
}
.card.selected{
background: #0173fb;
}
<section class='container'>
<ul class="cards">
<li class="cardItm">
<div class="card">
card items
</div>
</li>
</ul>
<button class='btn'>Submit</button>
</section>
let card = document.getElementsByClassName('card');
let allSelected = document.querySelectorAll('selected');
let btn = document.getElementsByClassName('btn');
for (var i = 0; i < card.length; i++) {
card[i].addEventListener('click', function(e) {
e.target.classList.add('selected');
})
}
In this code I am adding 'selected' class for the div onclick. I want this in pure javascript.. no jquery or any other library.
Thanks in advance.
try like this. Pure javascript.
document.addEventListener("DOMContentLoaded", function(event) {
document.getElementsByClassName('btn')[0].setAttribute("disabled","true");
});
let card = document.getElementsByClassName('card');
let btn = document.getElementsByClassName('btn');
for (var i = 0; i < card.length; i++) {
card[i].addEventListener('click', function(e) {
e.target.classList.toggle('selected');
if(card.length === document.getElementsByClassName('selected').length){
btn[0].removeAttribute("disabled");
}
else{
btn[0].setAttribute("disabled","true");
}
})
}
.card{
padding: 8px;
border: 1px solid #eee;
cursor: pointer;
}
ul, li{
list-style: none;
}
.card.selected{
background-color: rgb(155,155,155);
}
.btn{
padding: 10px;
margin: 10px;
}
<body>
<section class='container'>
<ul class="cards">
<li class="cardItm">
<div class="card">
card items 1
</div>
<div class="card">
card items 2
</div>
<div class="card">
card items 3
</div>
</li>
</ul>
<button class='btn'>Submit</button>
</section>
</body>
Or you can add eventListener without for. Like below:
let card = document.getElementsByClassName('card');
let btn = document.getElementsByClassName('btn');
document.body.addEventListener('click', function(e) {
if(e.target.classList.contains('card')){
e.target.classList.toggle('selected');
if(card.length === document.getElementsByClassName('selected').length){
btn[0].removeAttribute("disabled");
}
else{
btn[0].setAttribute("disabled","true");
}
}
});
Compare the available divs with the selected divs and enable the button if it matches.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
div{
height: 10px;
background-color: red;
margin-bottom: 10px;
}
.selected{
background-color: blue;
}
</style>
</head>
<body>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<button class="btn" disabled>Click</button>
<script>
let card = document.getElementsByClassName('card');
let btn = document.getElementsByClassName('btn');
for (var i = 0; i < card.length; i++) {
card[i].addEventListener('click', function(e) {
// add seclected class to clicke div
e.target.classList.add('selected');
// get all selected/clicked divs
let allSelected = document.querySelectorAll('.selected');
// compare available divs with selected divs
if(card.length === allSelected.length){
console.log("Enable button", btn[0])
btn[0].onclick = () => {
alert("Button clicked");
};
// enable button
btn[0].disabled = false;
}
});
}
</script>
</body>
</html>
EDIT: Troubleshooting (https://github.com/Bhanumathi-a/cards)
Your problem with your code is that you add the "selected" class on sub elements too! `` When you add a console log on the event handler you see that there are other elements than the divs get selected which gives you the filled array that matches the length of the available divs:
You can clearly see that the array contains more elements than only divs.
To fix this, find the nearest div.card element from the clicked children:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Member FDIC</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto&display=swap" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 0;
}
.container {
width: 100%;
margin: 0 auto;
min-width: 360px;
}
header {
display: block;
}
a.logo {
display: inline-block;
font-size: 50px;
color: #0173fb;
text-decoration: none;
padding: 15px;
}
nav {
display: inline-block;
}
.loanDetails {
background: #f8f8f8;
display: flex;
}
.cardBlk {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.cards {
display: flex;
flex-wrap: wrap;
list-style: none;
margin: 0;
padding: 0;
}
.cardItm {
display: flex;
padding: 10px;
}
#media(min-width:1240px) {
.container {
max-width: 1140px;
}
.cardItm {
width: 24%;
}
}
#media(min-width:1920px) {
.container {
max-width: 1820px;
}
.cardItm {
width: 33%;
}
}
.card {
background: #f8f8f8;
color: #2a2b2d;
border-radius: 10px;
padding: 15px 15px 30px 15px;
box-sizing: border-box;
width: 100%;
display: block;
overflow: hidden;
position: relative;
text-align: center;
cursor: pointer;
justify-content: center;
}
.card .info, .card .checked {
height: 39px;
width: 39px;
position: absolute;
top: 10px;
right: 10px;
border-radius: 50%;
}
.card .info {
background: url(assets/exclamation.png) no-repeat 0 0;
}
.card .checked {
background: url(assets/checked\ active.png) no-repeat 0 0;
}
.card img {
width: auto;
height: auto;
max-width: 50px;
margin: 25px auto;
}
.card.selected, .card:hover {
background: #0173fb;
color: #fff;
}
.card:hover .info, .card.selected .info {
background-image: url(assets/exclamation\ white.png);
}
.card:hover .checked, .card.selected .checked {
background-image: url(assets/checked\ inactive.png);
}
.btnBlk {
text-align: center;
display: block
}
.btn {
background: #0173fb;
border-radius: 25px;
padding: 10px 25px;
color: #fff;
text-align: center;
border: 1px solid #0173fb;
margin: 10px auto;
cursor: pointer;
display: inline-block;
text-transform: uppercase;
}
.btn:disabled {
background: #9ac5fb;
border-color: #9ac5fb;
cursor: default;
}
</style>
</head>
<body>
<header>
<div class="container">
Logo
<!-- <nav class="nav">
<ul>
<li>Dashboard</li>
<li>Welcome, John Doe</li>
</ul>
</nav> -->
</div>
</header>
<main>
<header class="loanDetails">
<div class="container">
loan
<progress value="30" max="100" id=progress>30%</progress>
</div>
</header>
<section class='container'>
<ul class="cards">
<li class="cardItm">
<div class="card 1">
<span class="checked"></span>
<img src="assets/location.png" alt="">
<div>
<h2>Get started</h2>
<span>(100% completed)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card 2">
<span class="info"></span>
<img src="assets/property.png" alt="">
<div>
<h2>Get started</h2>
<span>(Not Started)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card">
<span class="info"></span>
<img src="assets/income.png" alt="">
<div>
<h2>Get started</h2>
<span>(Not Started)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card">
<span class="checked"></span>
<img src="assets/assets.png" alt="">
<div>
<h2>Get started</h2>
<span>(50% completed)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card">
<span class="checked"></span>
<img src="assets/real estate.png" alt="">
<div>
<h2>Get started</h2>
<span>(70% completed)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card">
<span class="info"></span>
<img src="assets/declarations.png" alt="">
<div>
<h2>Get started</h2>
<span>(90% completed)</span>
</div>
</div>
</li>
<li class="cardItm">
<div class="card">
<span class="checked"></span>
<img src="assets/e-concent.png" alt="">
<div>
<h2>Get started</h2>
<span>(Not Started)</span>
</div>
</div>
</li>
</ul>
<div class="btnBlk">
<button class="btn" id="submitBtn" disabled>Submit Application</button>
</div>
</section>
</main>
<footer>
</footer>
<script>
let card = document.getElementsByClassName('card');
let btn = document.getElementsByClassName('btn');
let progress = document.getElementById('progress');
for (var i = 0; i < card.length; i++) {
card[i].addEventListener('click', function (e) {
let closest = e.target.closest("div.card");
closest.classList.add('selected');
progress.value = progress.value + 10;
let allSelected = document.querySelectorAll('div.selected');
if (card.length === allSelected.length) {
btn[0].onclick = () => {
console.log('clicked');
};
btn[0].disabled = false;
}
});
}
</script>
</body>
</html>
Hello this is my code and jsfiddle
<div id="section-2" class="section">
<div class="fullContentWrap">
<!-- client_logos_row -->
<div class="flexRow toLeft" style="left: 0%;">
<div class="box">
</div>
<div class="box">
</div>
<div class="box">
</div>
</div>
<div class="flexRow toLeft" style="left: 0%;">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<!-- flexRow toLeft -->
</div>
<!-- fullContentWrap -->
</div>
$(document).ready(function() {
console.log("interval doc ready");
var currToLeft = $('.toLeft').first();
currToLeft.addClass("toLeftActive");
var myInt = setInterval(intFunc,3000);
console.log('myInt set');
function intFunc() {
console.log('intFunc !');
currToLeft.animate({left: '-101%'}, "slow",function () {
$(this).removeClass("toLeftActive");
$(this).css("left",'0%');
currToLeft = $(this).next();
if (currToLeft.length === 0) {
currToLeft = $('.toLeft').first();
}
currToLeft.addClass('toLeftActive');
});
}
// intFunc
});
// document ready
.box {
width: 100px;
height: 100px;
}
.flexRow {
display: flex;
}
.toLeft{
display: none;
left: 100%;
}
.toLeftActive {
display: flex !important;
}
.flexRow:nth-child(1) .box:nth-child(1) {
background: blue;
}
.flexRow:nth-child(1) .box:nth-child(2) {
background: red;
}
.flexRow:nth-child(1) .box:nth-child(3) {
background: orange;
}
.flexRow:nth-child(2) .box:nth-child(1) {
background: aqua;
}
.flexRow:nth-child(2) .box:nth-child(2) {
background: green;
}
.flexRow:nth-child(2) .box:nth-child(3) {
background: brown;
}
div#section-2 {
position: relative;
}
div#section-2>.fullContentWrap {
position: inherit;
}
div#section-2>.fullContentWrap>.flexRow {
position: inherit;
justify-content: center;
}
div#section-2>.fullContentWrap>.flexRow>div {
position: inherit;
}
https://jsfiddle.net/2918ztze/
As you can guess I am making a slider. The first block should go out of the screen to the left and the other one should come from right to left:0 meanwhile.
I am not sure how this meanwhile part should be done, probably with some async coding, but how do I do it?