How to upload and preview 2 images in JavaScript - javascript

The first one is working while the other one is not uploading and neither previewing the image I want to upload. I want both the image uploader and preview. But the first one is working only. I am using the same JavaScript for the Image uploader and preview. Simple word the code for HTML is copied and JavaScript is the same too. Kindly change it and make both inputs work correctly.
// Design By
// - https://dribbble.com/shots/13992184-File-Uploader-Drag-Drop
// Select Upload-Area
const uploadArea = document.querySelector('#uploadArea')
// Select Drop-Zoon Area
const dropZoon = document.querySelector('#dropZoon');
// Loading Text
const loadingText = document.querySelector('#loadingText');
// Slect File Input
const fileInput = document.querySelector('#fileInput');
// Select Preview Image
const previewImage = document.querySelector('#previewImage');
// File-Details Area
const fileDetails = document.querySelector('#fileDetails');
// Uploaded File
const uploadedFile = document.querySelector('#uploadedFile');
// Uploaded File Info
const uploadedFileInfo = document.querySelector('#uploadedFileInfo');
// Uploaded File Name
const uploadedFileName = document.querySelector('.uploaded-file__name');
// Uploaded File Icon
const uploadedFileIconText = document.querySelector('.uploaded-file__icon-text');
// Uploaded File Counter
const uploadedFileCounter = document.querySelector('.uploaded-file__counter');
// ToolTip Data
const toolTipData = document.querySelector('.upload-area__tooltip-data');
// Images Types
const imagesTypes = [
"jpeg",
"png",
"svg",
"gif"
];
// Append Images Types Array Inisde Tooltip Data
toolTipData.innerHTML = [...imagesTypes].join(', .');
// When (drop-zoon) has (dragover) Event
dropZoon.addEventListener('dragover', function (event) {
// Prevent Default Behavior
event.preventDefault();
// Add Class (drop-zoon--over) On (drop-zoon)
dropZoon.classList.add('drop-zoon--over');
});
// When (drop-zoon) has (dragleave) Event
dropZoon.addEventListener('dragleave', function (event) {
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove('drop-zoon--over');
});
// When (drop-zoon) has (drop) Event
dropZoon.addEventListener('drop', function (event) {
// Prevent Default Behavior
event.preventDefault();
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove('drop-zoon--over');
// Select The Dropped File
const file = event.dataTransfer.files[0];
// Call Function uploadFile(), And Send To Her The Dropped File :)
uploadFile(file);
});
// When (drop-zoon) has (click) Event
dropZoon.addEventListener('click', function (event) {
// Click The (fileInput)
fileInput.click();
});
// When (fileInput) has (change) Event
fileInput.addEventListener('change', function (event) {
// Select The Chosen File
const file = event.target.files[0];
// Call Function uploadFile(), And Send To Her The Chosen File :)
uploadFile(file);
});
// Upload File Function
function uploadFile(file) {
// FileReader()
const fileReader = new FileReader();
// File Type
const fileType = file.type;
// File Size
const fileSize = file.size;
// If File Is Passed from the (File Validation) Function
if (fileValidate(fileType, fileSize)) {
// Add Class (drop-zoon--Uploaded) on (drop-zoon)
dropZoon.classList.add('drop-zoon--Uploaded');
// Show Loading-text
loadingText.style.display = "block";
// Hide Preview Image
previewImage.style.display = 'none';
// Remove Class (uploaded-file--open) From (uploadedFile)
uploadedFile.classList.remove('uploaded-file--open');
// Remove Class (uploaded-file__info--active) from (uploadedFileInfo)
uploadedFileInfo.classList.remove('uploaded-file__info--active');
// After File Reader Loaded
fileReader.addEventListener('load', function () {
// After Half Second
setTimeout(function () {
// Add Class (upload-area--open) On (uploadArea)
uploadArea.classList.add('upload-area--open');
// Hide Loading-text (please-wait) Element
loadingText.style.display = "none";
// Show Preview Image
previewImage.style.display = 'block';
// Add Class (file-details--open) On (fileDetails)
fileDetails.classList.add('file-details--open');
// Add Class (uploaded-file--open) On (uploadedFile)
uploadedFile.classList.add('uploaded-file--open');
// Add Class (uploaded-file__info--active) On (uploadedFileInfo)
uploadedFileInfo.classList.add('uploaded-file__info--active');
}, 500); // 0.5s
// Add The (fileReader) Result Inside (previewImage) Source
previewImage.setAttribute('src', fileReader.result);
// Add File Name Inside Uploaded File Name
uploadedFileName.innerHTML = file.name;
// Call Function progressMove();
progressMove();
});
// Read (file) As Data Url
fileReader.readAsDataURL(file);
} else { // Else
this; // (this) Represent The fileValidate(fileType, fileSize) Function
};
};
// Progress Counter Increase Function
function progressMove() {
// Counter Start
let counter = 0;
// After 600ms
setTimeout(() => {
// Every 100ms
let counterIncrease = setInterval(() => {
// If (counter) is equle 100
if (counter === 100) {
// Stop (Counter Increase)
clearInterval(counterIncrease);
} else { // Else
// plus 10 on counter
counter = counter + 10;
// add (counter) vlaue inisde (uploadedFileCounter)
uploadedFileCounter.innerHTML = `${counter}%`
}
}, 100);
}, 600);
};
// Simple File Validate Function
function fileValidate(fileType, fileSize) {
// File Type Validation
let isImage = imagesTypes.filter((type) => fileType.indexOf(`image/${type}`) !== -1);
// If The Uploaded File Type Is 'jpeg'
if (isImage[0] === 'jpeg') {
// Add Inisde (uploadedFileIconText) The (jpg) Value
uploadedFileIconText.innerHTML = 'jpg';
} else { // else
// Add Inisde (uploadedFileIconText) The Uploaded File Type
uploadedFileIconText.innerHTML = isImage[0];
};
// If The Uploaded File Is An Image
if (isImage.length !== 0) {
// Check, If File Size Is 2MB or Less
if (fileSize <= 2000000) { // 2MB :)
return true;
} else { // Else File Size
return alert('Please Your File Should be 2 Megabytes or Less');
};
} else { // Else File Type
return alert('Please make sure to upload An Image File Type');
};
};
// :)
/* General Styles */
* {
box-sizing: border-box;
}
:root {
--clr-white: rgb(255, 255, 255);
--clr-black: rgb(0, 0, 0);
--clr-light: rgb(245, 248, 255);
--clr-light-gray: rgb(196, 195, 196);
--clr-blue: rgb(63, 134, 255);
--clr-light-blue: rgb(171, 202, 255);
}
body {
margin: 0;
padding: 0;
background-color: var(--clr-light);
color: var(--clr-black);
font-family: 'Poppins', sans-serif;
font-size: 1.125rem;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* End General Styles */
/* Upload Area */
.upload-area {
width: 100%;
max-width: 25rem;
background-color: var(--clr-white);
box-shadow: 0 10px 60px rgb(218, 229, 255);
border: 2px solid var(--clr-light-blue);
border-radius: 24px;
padding: 2rem 1.875rem 5rem 1.875rem;
margin: 0.625rem;
text-align: center;
}
.upload-area--open { /* Slid Down Animation */
animation: slidDown 500ms ease-in-out;
}
#keyframes slidDown {
from {
height: 28.125rem; /* 450px */
}
to {
height: 35rem; /* 560px */
}
}
/* Header */
.upload-area__header {
}
.upload-area__title {
font-size: 1.8rem;
font-weight: 500;
margin-bottom: 0.3125rem;
}
.upload-area__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin-top: 0;
}
.upload-area__tooltip {
position: relative;
color: var(--clr-light-blue);
cursor: pointer;
transition: color 300ms ease-in-out;
}
.upload-area__tooltip:hover {
color: var(--clr-blue);
}
.upload-area__tooltip-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -125%);
min-width: max-content;
background-color: var(--clr-white);
color: var(--clr-blue);
border: 1px solid var(--clr-light-blue);
padding: 0.625rem 1.25rem;
font-weight: 500;
opacity: 0;
visibility: hidden;
transition: none 300ms ease-in-out;
transition-property: opacity, visibility;
}
.upload-area__tooltip:hover .upload-area__tooltip-data {
opacity: 1;
visibility: visible;
}
/* Drop Zoon */
.upload-area__drop-zoon {
position: relative;
height: 11.25rem; /* 180px */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border: 2px dashed var(--clr-light-blue);
border-radius: 15px;
margin-top: 2.1875rem;
cursor: pointer;
transition: border-color 300ms ease-in-out;
}
.upload-area__drop-zoon:hover {
border-color: var(--clr-blue);
}
.drop-zoon__icon {
display: flex;
font-size: 3.75rem;
color: var(--clr-blue);
transition: opacity 300ms ease-in-out;
}
.drop-zoon__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin: 0;
margin-top: 0.625rem;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__icon,
.drop-zoon:hover .drop-zoon__paragraph {
opacity: 0.7;
}
.drop-zoon__loading-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: var(--clr-light-blue);
z-index: 10;
}
.drop-zoon__preview-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 0.3125rem;
border-radius: 10px;
display: none;
z-index: 1000;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__preview-image {
opacity: 0.8;
}
.drop-zoon__file-input {
display: none;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--over {
border-color: var(--clr-blue);
}
.drop-zoon--over .drop-zoon__icon,
.drop-zoon--over .drop-zoon__paragraph {
opacity: 0.7;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--Uploaded {
}
.drop-zoon--Uploaded .drop-zoon__icon,
.drop-zoon--Uploaded .drop-zoon__paragraph {
display: none;
}
/* File Details Area */
.upload-area__file-details {
height: 0;
visibility: hidden;
opacity: 0;
text-align: left;
transition: none 500ms ease-in-out;
transition-property: opacity, visibility;
transition-delay: 500ms;
}
/* (duploaded-file--open) Modifier Class */
.file-details--open {
height: auto;
visibility: visible;
opacity: 1;
}
.file-details__title {
font-size: 1.125rem;
font-weight: 500;
color: var(--clr-light-gray);
}
/* Uploaded File */
.uploaded-file {
display: flex;
align-items: center;
padding: 0.625rem 0;
visibility: hidden;
opacity: 0;
transition: none 500ms ease-in-out;
transition-property: visibility, opacity;
}
/* (duploaded-file--open) Modifier Class */
.uploaded-file--open {
visibility: visible;
opacity: 1;
}
.uploaded-file__icon-container {
position: relative;
margin-right: 0.3125rem;
}
.uploaded-file__icon {
font-size: 3.4375rem;
color: var(--clr-blue);
}
.uploaded-file__icon-text {
position: absolute;
top: 1.5625rem;
left: 50%;
transform: translateX(-50%);
font-size: 0.9375rem;
font-weight: 500;
color: var(--clr-white);
}
.uploaded-file__info {
position: relative;
top: -0.3125rem;
width: 100%;
display: flex;
justify-content: space-between;
}
.uploaded-file__info::before,
.uploaded-file__info::after {
content: '';
position: absolute;
bottom: -0.9375rem;
width: 0;
height: 0.5rem;
background-color: #ebf2ff;
border-radius: 0.625rem;
}
.uploaded-file__info::before {
width: 100%;
}
.uploaded-file__info::after {
width: 100%;
background-color: var(--clr-blue);
}
/* Progress Animation */
.uploaded-file__info--active::after {
animation: progressMove 800ms ease-in-out;
animation-delay: 300ms;
}
#keyframes progressMove {
from {
width: 0%;
background-color: transparent;
}
to {
width: 100%;
background-color: var(--clr-blue);
}
}
.uploaded-file__name {
width: 100%;
max-width: 6.25rem; /* 100px */
display: inline-block;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.uploaded-file__counter {
font-size: 1rem;
color: var(--clr-light-gray);
}
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
<div class="mb-5 mt-5"></div>
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->

In JavaScript file you are using document.querySelector("")
That chooses only the first element in the HTML and you can't duplicate the two uploader and use the same selector in JavaScript.
You can with JavaScript select the two uploader & make the functions for the two uploaders with loop as an example.
If you need array of the elements you can use document.querySelectorAll("").

Since IDs such as #uploadArea, #dropZoon, etc. have become duplicated in the html code, then accordingly you install all handlers only for the first element.
I have slightly corrected your example so that you can install a lot of loaders:
// Design By
// - https://dribbble.com/shots/13992184-File-Uploader-Drag-Drop
uploadHandler({
uploadArea: document.querySelector("#uploadArea"),
dropZoon: document.querySelector("#dropZoon"),
loadingText: document.querySelector("#loadingText"),
fileInput: document.querySelector("#fileInput"),
previewImage: document.querySelector("#previewImage"),
fileDetails: document.querySelector("#fileDetails"),
uploadedFile: document.querySelector("#uploadedFile"),
uploadedFileInfo: document.querySelector("#uploadedFileInfo"),
uploadedFileName: document.querySelector(".uploaded-file__name"),
uploadedFileIconText: document.querySelector(".uploaded-file__icon-text"),
uploadedFileCounter: document.querySelector(".uploaded-file__counter"),
toolTipData: document.querySelector(".upload-area__tooltip-data"),
});
uploadHandler({
uploadArea: document.querySelector("#uploadArea-2"),
dropZoon: document.querySelector("#dropZoon-2"),
loadingText: document.querySelector("#loadingText-2"),
fileInput: document.querySelector("#fileInput-2"),
previewImage: document.querySelector("#previewImage-2"),
fileDetails: document.querySelector("#fileDetails-2"),
uploadedFile: document.querySelector("#uploadedFile-2"),
uploadedFileInfo: document.querySelector("#uploadedFileInfo-2"),
uploadedFileName: document.querySelector(".uploaded-file__name-2"),
uploadedFileIconText: document.querySelector(".uploaded-file__icon-text-2"),
uploadedFileCounter: document.querySelector(".uploaded-file__counter-2"),
toolTipData: document.querySelector(".upload-area__tooltip-data-2"),
});
function uploadHandler({
uploadArea,
dropZoon,
loadingText,
fileInput,
previewImage,
fileDetails,
uploadedFile,
uploadedFileInfo,
uploadedFileName,
uploadedFileIconText,
uploadedFileCounter,
toolTipData,
}) {
// Images Types
const imagesTypes = ["jpeg", "png", "svg", "gif"];
// Append Images Types Array Inisde Tooltip Data
toolTipData.innerHTML = [...imagesTypes].join(", .");
// When (drop-zoon) has (dragover) Event
dropZoon.addEventListener("dragover", function (event) {
// Prevent Default Behavior
event.preventDefault();
// Add Class (drop-zoon--over) On (drop-zoon)
dropZoon.classList.add("drop-zoon--over");
});
// When (drop-zoon) has (dragleave) Event
dropZoon.addEventListener("dragleave", function (event) {
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove("drop-zoon--over");
});
// When (drop-zoon) has (drop) Event
dropZoon.addEventListener("drop", function (event) {
// Prevent Default Behavior
event.preventDefault();
// Remove Class (drop-zoon--over) from (drop-zoon)
dropZoon.classList.remove("drop-zoon--over");
// Select The Dropped File
const file = event.dataTransfer.files[0];
// Call Function uploadFile(), And Send To Her The Dropped File :)
uploadFile(file);
});
// When (drop-zoon) has (click) Event
dropZoon.addEventListener("click", function (event) {
// Click The (fileInput)
fileInput.click();
});
// When (fileInput) has (change) Event
fileInput.addEventListener("change", function (event) {
// Select The Chosen File
const file = event.target.files[0];
// Call Function uploadFile(), And Send To Her The Chosen File :)
uploadFile(file);
});
// Upload File Function
function uploadFile(file) {
// FileReader()
const fileReader = new FileReader();
// File Type
const fileType = file.type;
// File Size
const fileSize = file.size;
// If File Is Passed from the (File Validation) Function
if (fileValidate(fileType, fileSize)) {
// Add Class (drop-zoon--Uploaded) on (drop-zoon)
dropZoon.classList.add("drop-zoon--Uploaded");
// Show Loading-text
loadingText.style.display = "block";
// Hide Preview Image
previewImage.style.display = "none";
// Remove Class (uploaded-file--open) From (uploadedFile)
uploadedFile.classList.remove("uploaded-file--open");
// Remove Class (uploaded-file__info--active) from (uploadedFileInfo)
uploadedFileInfo.classList.remove("uploaded-file__info--active");
// After File Reader Loaded
fileReader.addEventListener("load", function () {
// After Half Second
setTimeout(function () {
// Add Class (upload-area--open) On (uploadArea)
uploadArea.classList.add("upload-area--open");
// Hide Loading-text (please-wait) Element
loadingText.style.display = "none";
// Show Preview Image
previewImage.style.display = "block";
// Add Class (file-details--open) On (fileDetails)
fileDetails.classList.add("file-details--open");
// Add Class (uploaded-file--open) On (uploadedFile)
uploadedFile.classList.add("uploaded-file--open");
// Add Class (uploaded-file__info--active) On (uploadedFileInfo)
uploadedFileInfo.classList.add("uploaded-file__info--active");
}, 500); // 0.5s
// Add The (fileReader) Result Inside (previewImage) Source
previewImage.setAttribute("src", fileReader.result);
// Add File Name Inside Uploaded File Name
uploadedFileName.innerHTML = file.name;
// Call Function progressMove();
progressMove();
});
// Read (file) As Data Url
fileReader.readAsDataURL(file);
} else {
// Else
this; // (this) Represent The fileValidate(fileType, fileSize) Function
}
}
// Progress Counter Increase Function
function progressMove() {
// Counter Start
let counter = 0;
// After 600ms
setTimeout(() => {
// Every 100ms
let counterIncrease = setInterval(() => {
// If (counter) is equle 100
if (counter === 100) {
// Stop (Counter Increase)
clearInterval(counterIncrease);
} else {
// Else
// plus 10 on counter
counter = counter + 10;
// add (counter) vlaue inisde (uploadedFileCounter)
uploadedFileCounter.innerHTML = `${counter}%`;
}
}, 100);
}, 600);
}
// Simple File Validate Function
function fileValidate(fileType, fileSize) {
// File Type Validation
let isImage = imagesTypes.filter(
(type) => fileType.indexOf(`image/${type}`) !== -1
);
// If The Uploaded File Type Is 'jpeg'
if (isImage[0] === "jpeg") {
// Add Inisde (uploadedFileIconText) The (jpg) Value
uploadedFileIconText.innerHTML = "jpg";
} else {
// else
// Add Inisde (uploadedFileIconText) The Uploaded File Type
uploadedFileIconText.innerHTML = isImage[0];
}
// If The Uploaded File Is An Image
if (isImage.length !== 0) {
// Check, If File Size Is 2MB or Less
if (fileSize <= 2000000) {
// 2MB :)
return true;
} else {
// Else File Size
return alert("Please Your File Should be 2 Megabytes or Less");
}
} else {
// Else File Type
return alert("Please make sure to upload An Image File Type");
}
}
}
// :)
/* General Styles */
* {
box-sizing: border-box;
}
:root {
--clr-white: rgb(255, 255, 255);
--clr-black: rgb(0, 0, 0);
--clr-light: rgb(245, 248, 255);
--clr-light-gray: rgb(196, 195, 196);
--clr-blue: rgb(63, 134, 255);
--clr-light-blue: rgb(171, 202, 255);
}
body {
margin: 0;
padding: 0;
background-color: var(--clr-light);
color: var(--clr-black);
font-family: 'Poppins', sans-serif;
font-size: 1.125rem;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
/* End General Styles */
/* Upload Area */
.upload-area {
width: 100%;
max-width: 25rem;
background-color: var(--clr-white);
box-shadow: 0 10px 60px rgb(218, 229, 255);
border: 2px solid var(--clr-light-blue);
border-radius: 24px;
padding: 2rem 1.875rem 5rem 1.875rem;
margin: 0.625rem;
text-align: center;
}
.upload-area--open { /* Slid Down Animation */
animation: slidDown 500ms ease-in-out;
}
#keyframes slidDown {
from {
height: 28.125rem; /* 450px */
}
to {
height: 35rem; /* 560px */
}
}
/* Header */
.upload-area__header {
}
.upload-area__title {
font-size: 1.8rem;
font-weight: 500;
margin-bottom: 0.3125rem;
}
.upload-area__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin-top: 0;
}
.upload-area__tooltip {
position: relative;
color: var(--clr-light-blue);
cursor: pointer;
transition: color 300ms ease-in-out;
}
.upload-area__tooltip:hover {
color: var(--clr-blue);
}
.upload-area__tooltip-data {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -125%);
min-width: max-content;
background-color: var(--clr-white);
color: var(--clr-blue);
border: 1px solid var(--clr-light-blue);
padding: 0.625rem 1.25rem;
font-weight: 500;
opacity: 0;
visibility: hidden;
transition: none 300ms ease-in-out;
transition-property: opacity, visibility;
}
.upload-area__tooltip:hover .upload-area__tooltip-data {
opacity: 1;
visibility: visible;
}
/* Drop Zoon */
.upload-area__drop-zoon {
position: relative;
height: 11.25rem; /* 180px */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
border: 2px dashed var(--clr-light-blue);
border-radius: 15px;
margin-top: 2.1875rem;
cursor: pointer;
transition: border-color 300ms ease-in-out;
}
.upload-area__drop-zoon:hover {
border-color: var(--clr-blue);
}
.drop-zoon__icon {
display: flex;
font-size: 3.75rem;
color: var(--clr-blue);
transition: opacity 300ms ease-in-out;
}
.drop-zoon__paragraph {
font-size: 0.9375rem;
color: var(--clr-light-gray);
margin: 0;
margin-top: 0.625rem;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__icon,
.drop-zoon:hover .drop-zoon__paragraph {
opacity: 0.7;
}
.drop-zoon__loading-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: var(--clr-light-blue);
z-index: 10;
}
.drop-zoon__preview-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
padding: 0.3125rem;
border-radius: 10px;
display: none;
z-index: 1000;
transition: opacity 300ms ease-in-out;
}
.drop-zoon:hover .drop-zoon__preview-image {
opacity: 0.8;
}
.drop-zoon__file-input {
display: none;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--over {
border-color: var(--clr-blue);
}
.drop-zoon--over .drop-zoon__icon,
.drop-zoon--over .drop-zoon__paragraph {
opacity: 0.7;
}
/* (drop-zoon--over) Modifier Class */
.drop-zoon--Uploaded {
}
.drop-zoon--Uploaded .drop-zoon__icon,
.drop-zoon--Uploaded .drop-zoon__paragraph {
display: none;
}
/* File Details Area */
.upload-area__file-details {
height: 0;
visibility: hidden;
opacity: 0;
text-align: left;
transition: none 500ms ease-in-out;
transition-property: opacity, visibility;
transition-delay: 500ms;
}
/* (duploaded-file--open) Modifier Class */
.file-details--open {
height: auto;
visibility: visible;
opacity: 1;
}
.file-details__title {
font-size: 1.125rem;
font-weight: 500;
color: var(--clr-light-gray);
}
/* Uploaded File */
.uploaded-file {
display: flex;
align-items: center;
padding: 0.625rem 0;
visibility: hidden;
opacity: 0;
transition: none 500ms ease-in-out;
transition-property: visibility, opacity;
}
/* (duploaded-file--open) Modifier Class */
.uploaded-file--open {
visibility: visible;
opacity: 1;
}
.uploaded-file__icon-container {
position: relative;
margin-right: 0.3125rem;
}
.uploaded-file__icon {
font-size: 3.4375rem;
color: var(--clr-blue);
}
.uploaded-file__icon-text {
position: absolute;
top: 1.5625rem;
left: 50%;
transform: translateX(-50%);
font-size: 0.9375rem;
font-weight: 500;
color: var(--clr-white);
}
.uploaded-file__info {
position: relative;
top: -0.3125rem;
width: 100%;
display: flex;
justify-content: space-between;
}
.uploaded-file__info::before,
.uploaded-file__info::after {
content: '';
position: absolute;
bottom: -0.9375rem;
width: 0;
height: 0.5rem;
background-color: #ebf2ff;
border-radius: 0.625rem;
}
.uploaded-file__info::before {
width: 100%;
}
.uploaded-file__info::after {
width: 100%;
background-color: var(--clr-blue);
}
/* Progress Animation */
.uploaded-file__info--active::after {
animation: progressMove 800ms ease-in-out;
animation-delay: 300ms;
}
#keyframes progressMove {
from {
width: 0%;
background-color: transparent;
}
to {
width: 100%;
background-color: var(--clr-blue);
}
}
.uploaded-file__name {
width: 100%;
max-width: 6.25rem; /* 100px */
display: inline-block;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.uploaded-file__counter {
font-size: 1rem;
color: var(--clr-light-gray);
}
<!-- Upload Area -->
<div id="uploadArea" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo" class="uploaded-file__info">
<span class="uploaded-file__name">Proejct 1</span>
<span class="uploaded-file__counter">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
<div class="mb-5 mt-5"></div>
<!-- Upload Area -->
<div id="uploadArea-2" class="upload-area">
<!-- Header -->
<div class="upload-area__header">
<h1 class="upload-area__title">Upload your file</h1>
<p class="upload-area__paragraph">
File should be an image
<strong class="upload-area__tooltip">
Like
<span class="upload-area__tooltip-data-2"></span> <!-- Data Will be Comes From Js -->
</strong>
</p>
</div>
<!-- End Header -->
<!-- Drop Zoon -->
<div id="dropZoon-2" class="upload-area__drop-zoon drop-zoon">
<span class="drop-zoon__icon">
<i class='bx bxs-file-image'></i>
</span>
<p class="drop-zoon__paragraph">Drop your file here or Click to browse</p>
<span id="loadingText-2" class="drop-zoon__loading-text">Please Wait</span>
<img src="" alt="Preview Image" id="previewImage-2" class="drop-zoon__preview-image" draggable="false">
<input type="file" id="fileInput-2" class="drop-zoon__file-input" accept="image/*">
</div>
<!-- End Drop Zoon -->
<!-- File Details -->
<div id="fileDetails-2" class="upload-area__file-details file-details">
<h3 class="file-details__title">Uploaded File</h3>
<div id="uploadedFile-2" class="uploaded-file">
<div class="uploaded-file__icon-container">
<i class='bx bxs-file-blank uploaded-file__icon'></i>
<span class="uploaded-file__icon-text-2"></span> <!-- Data Will be Comes From Js -->
</div>
<div id="uploadedFileInfo-2" class="uploaded-file__info">
<span class="uploaded-file__name-2">Proejct 1</span>
<span class="uploaded-file__counter-2">0%</span>
</div>
</div>
</div>
<!-- End File Details -->
</div>
<!-- End Upload Area -->
In fact, all your code was wrapped in a separate function, to which the arguments of the same name are passed.
Of course, in my opinion, for the final result, this should be refactored for final use, using querySelectorAll for a list of root elements, followed by obtaining individual nested elements with querySelector.

Related

API images not displayed within modal

I am a beginner and I am using several tutorials to learn and create a project. I am using the NASA APOD API to display images. However, I want to display the image when clicked within a modal. For some reason the image when clicked is displaying the modal, but without the image. How do I click on the image and display it within the modal.
const resultsNav = document.getElementById("resultsNav");
const favoritesNav = document.getElementById("favoritesNav");
const imagesContainer = document.querySelector(".images-container");
const saveConfirmed = document.querySelector(".save-confirmed");
const loader = document.querySelector(".loader");
// NASA API
const count = 3;
const apiKey = 'DEMO_KEY';
const apiUrl = `https://api.nasa.gov/planetary/apod?api_key=${apiKey}&count=${count}`;
let resultsArray = [];
let favorites = {};
// Show Content
function showContent(page) {
window.scrollTo({ top: 0, behavior: "instant" });
if (page === "results") {
resultsNav.classList.remove("hidden");
favoritesNav.classList.add("hidden");
} else {
resultsNav.classList.add("hidden");
favoritesNav.classList.remove("hidden");
}
loader.classList.add("hidden");
}
// Create DOM Nodes
function createDOMNodes(page) {
const currentArray =
page === "results" ? resultsArray : Object.values(favorites);
currentArray.forEach((result) => {
// Card Container
const card = document.createElement("div");
card.classList.add("card");
// Link that wraps the image
const link = document.createElement("a");
// link.href = result.hdurl; -- full size image display when clicked
// Get the modal
var modal = document.getElementById("myModal");
// Get the image and insert it inside the modal - use its "alt" text as a caption
var img = document.getElementById("myImg");
var modalImg = document.getElementById("img01");
var captionText = document.getElementById("caption");
img.onclick = function(){
modal.style.display = "block";
modalImg.src = this.src;
captionText.innerHTML = this.alt;
}
// Get the <span> element that closes the modal
var span = document.getElementsByClassName("close")[0];
// When the user clicks on <span> (x), close the modal
span.onclick = function() {
modal.style.display = "none";
}
// Image
const image = document.createElement("img");
image.src = result.url;
image.alt = "NASA Picture of the Day";
image.loading = "lazy";
image.classList.add("card-img-top");
// Card Body
const cardBody = document.createElement("div");
cardBody.classList.add("card-body");
// Card Title
const cardTitle = document.createElement("h5");
cardTitle.classList.add("card-title");
cardTitle.textContent = result.title;
// Save Text
const saveText = document.createElement("p");
saveText.classList.add("clickable");
if (page === "results") {
saveText.textContent = "Add To Favorites";
saveText.setAttribute("onclick", `saveFavorite('${result.url}')`);
} else {
saveText.textContent = "Remove Favorite";
saveText.setAttribute("onclick", `removeFavorite('${result.url}')`);
}
// Card Text
const cardText = document.createElement("p");
cardText.textContent = result.explanation;
// Footer Conatiner
const footer = document.createElement("small");
footer.classList.add("text-muted");
// Date
const date = document.createElement("strong");
date.textContent = result.date;
// Copyright
const copyrightResult =
result.copyright === undefined ? "" : result.copyright;
const copyright = document.createElement("span");
copyright.textContent = ` ${copyrightResult}`;
// Append everything together
footer.append(date, copyright);
cardBody.append(cardTitle, saveText, cardText, footer); //hide to make image display
link.appendChild(image);
card.append(link); // hide cardBody
// Append to image container
imagesContainer.appendChild(card);
});
}
// Update the DOM
function updateDOM(page) {
// Get favorites from local storage
if (localStorage.getItem("nasaFavorites")) {
favorites = JSON.parse(localStorage.getItem("nasaFavorites"));
}
imagesContainer.textContent = "";
createDOMNodes(page);
showContent(page);
}
// Get 10 images from NASA API
async function getNasaPictures() {
// Show Loader
loader.classList.remove("hidden");
try {
const response = await fetch(apiUrl);
resultsArray = await response.json();
updateDOM("results");
} catch (error) {
// Catch Error Here
}
}
// Add result to favorites
function saveFavorite(itemUrl) {
// Loop through the results array to select favorite
resultsArray.forEach((item) => {
if (item.url.includes(itemUrl) && !favorites[itemUrl]) {
favorites[itemUrl] = item;
// Show save confirmation for 2 seconds
saveConfirmed.hidden = false;
setTimeout(() => {
saveConfirmed.hidden = true;
}, 2000);
// Set Favorites in Local Storage
localStorage.setItem("nasaFavorites", JSON.stringify(favorites));
}
});
}
// Remove item from favorites
function removeFavorite(itemUrl) {
if (favorites[itemUrl]) {
delete favorites[itemUrl];
localStorage.setItem("nasaFavorites", JSON.stringify(favorites));
updateDOM("favorites");
}
}
// On Load
getNasaPictures();
.container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 3% 1fr 0.1fr;
gap: 0px 0px;
grid-auto-flow: row;
grid-template-areas:
"header"
"content"
}
.hero {
grid-area: hero;
background-color: blue;
}
.content {
grid-area: content;
background-color: orange;
align-self: center;
justify-self: center;
}
html {
box-sizing: border-box;
}
body {
margin: 0;
background: whitesmoke;
overflow-x: hidden;
font-family: Verdana, sans-serif;
font-size: 1rem;
line-height: 1.8rem;
}
.loader {
position: fixed;
z-index: 40;
background: whitesmoke;
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
}
/* Navigation */
.navigation-container {
position: fixed;
top: 0;
}
.navigation-items {
display: flex;
justify-content: center;
}
.background {
background: whitesmoke;
position: fixed;
right: 0;
width: 100%;
height: 60px;
z-index: -1;
}
.clickable {
color: #0b3d91;
cursor: pointer;
user-select: none;
}
.clickable:hover {
color: #fc3d21;
}
/* Images Container */
.images-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.card {
margin: 10px 10px 10px;
width: 300px;
height: 300px;
}
.card-img-top {
width: 300px;
height: 300px;
}
.card-body {
padding: 20px;
}
.card-title {
margin: 10px auto;
font-size: 24px;
}
/* Save Confirmation */
.save-confirmed {
background: white;
padding: 8px 16px;
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
position: fixed;
bottom: 25px;
right: 50px;
z-index: 500;
}
/* Hidden */
.hidden {
display: none;
}
.brand {
float: right;
}
.fave {
margin-right: 50%;
}
#myImg {
border-radius: 5px;
cursor: pointer;
transition: 0.3s;
}
/* #myImg:hover {opacity: 0.7;} */
/* The Modal (background) */
.modal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: rgb(0, 0, 0);
/* Fallback color */
background-color: rgba(0, 0, 0, 0.9);
/* Black w/ opacity */
}
/* Modal Content (image) */
.modal-content {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
}
/* Caption of Modal Image */
#caption {
margin: auto;
display: block;
width: 80%;
max-width: 700px;
text-align: center;
color: #ccc;
padding: 10px 0;
height: 150px;
}
/* The Close Button */
.close {
position: absolute;
top: 15px;
right: 35px;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
transition: 0.3s;
}
.close:hover,
.close:focus {
color: #bbb;
text-decoration: none;
cursor: pointer;
}
/* 100% Image Width on Smaller Screens */
#media only screen and (max-width: 700px) {
.modal-content {
width: 100%;
}
}
<!-- Loader -->
<div class="loader hidden">
<img src="rocket.svg" alt="Rocket Icon" />
</div>
<!-- Container -->
<div class="container">
<div class="header">
<div class="navigation-container">
<span class="background"></span>
<!-- Results Nav -->
<span class="navigation-items" id="resultsNav">
</span>
<!-- Favorites Nav -->
<span class="navigation-items hidden" id="favoritesNav">
</span>
</div>
</div>
<div class="content">
<div class="container-fluid">
<div class="row">
<div class="column">
<div id="myImg" alt="Snow" class="images-container"></div>
</div>
</div>
</div>
</div>
<!-- The Modal -->
<div id="myModal" class="modal">
<span class="close">×</span>
<img class="modal-content" id="img01">
<div id="caption"></div>
</div>
</div>
In your img.onclick function/event listener (at line 51 of your JS), your this points to the parent instead of the image itself.
For a quick fix, try replacing your this with event.target (Basically, event.target.src in place of this.src and event.target.alt in place of this.alt at lines 56 and 57 of your current JS Fiddle)

Add a button to change to dark mode in html website

I have added a button on my site which let's the users change to dark or light mode whenever they want. I added the button with a moon icon on it, but the problem is that I want that the moon icon changes to sun icon when the user is in dark mode. And changes to moon icon when user is in light mode.
function myfunction(e) {
console.log("you clicked");
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
<button class="btn"><img src='moon.png'></img></button>
The .inverted class in js is because I don't want the images to invert their colors.. so I gave all the images a class='inverted'
So, this is what I've done and someone please let me know how I should change the icon to moon and sun depending on the current mode (light or dark)
Thanks!
You could add the sun as another image to the button and change the visibility of the two images via your .dark-mode css class.
So whenever the .dark-mode class is present the moon gets hidden and the sun gets shown.
function myfunction(e) {
console.log("you clicked");
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
/* button handling */
.moon {
display: block;
}
.sun {
display: none;
}
.dark-mode .moon {
display: none;
}
.dark-mode .sun {
display: block;
}
<button class="btn">
<img class="moon" src="moon.png" alt="moon"></img>
<img class="sun" src="sun.png" alt="sun"></img>
</button>
You could go with the CSS approach as in #Fabian's answer. If you would like to go with JS, you could simply use a flag to indicate whether or not the user switched to dark mode, and dynamically set the icon based on it.
let isDarkMode = document.documentElement.classList.contains("dark-mode");
function myfunction(e) {
document.documentElement.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
e.currentTarget.querySelector("img").src = isDarkMode ? "sun.png" : "moon.png";
}
You can use the below reference for the toggle button from light mode to dark mode and dark mode to light mode.
body {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-checkbox {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.toggle-slot {
position: relative;
height: 10em;
width: 20em;
border: 5px solid #e4e7ec;
border-radius: 10em;
background-color: white;
box-shadow: 0px 10px 25px #e4e7ec;
transition: background-color 250ms;
}
.toggle-checkbox:checked ~ .toggle-slot {
background-color: #374151;
}
.toggle-button {
transform: translate(11.75em, 1.75em);
position: absolute;
height: 6.5em;
width: 6.5em;
border-radius: 50%;
background-color: #ffeccf;
box-shadow: inset 0px 0px 0px 0.75em #ffbb52;
transition: background-color 250ms, border-color 250ms, transform 500ms cubic-bezier(.26,2,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .toggle-button {
background-color: #485367;
box-shadow: inset 0px 0px 0px 0.75em white;
transform: translate(1.75em, 1.75em);
}
.sun-icon {
position: absolute;
height: 6em;
width: 6em;
color: #ffbb52;
}
.sun-icon-wrapper {
position: absolute;
height: 6em;
width: 6em;
opacity: 1;
transform: translate(2em, 2em) rotate(15deg);
transform-origin: 50% 50%;
transition: opacity 150ms, transform 500ms cubic-bezier(.26,2,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .sun-icon-wrapper {
opacity: 0;
transform: translate(3em, 2em) rotate(0deg);
}
.moon-icon {
position: absolute;
height: 6em;
width: 6em;
color: white;
}
.moon-icon-wrapper {
position: absolute;
height: 6em;
width: 6em;
opacity: 0;
transform: translate(11em, 2em) rotate(0deg);
transform-origin: 50% 50%;
transition: opacity 150ms, transform 500ms cubic-bezier(.26,2.5,.46,.71);
}
.toggle-checkbox:checked ~ .toggle-slot .moon-icon-wrapper {
opacity: 1;
transform: translate(12em, 2em) rotate(-15deg);
}
<head>
<script src="https://code.iconify.design/1/1.0.4/iconify.min.js"> </script>
</head>
<label>
<input class='toggle-checkbox' type='checkbox'>
<div class='toggle-slot'>
<div class='sun-icon-wrapper'>
<div class="iconify sun-icon" data-icon="feather-sun" data-inline="false"></div>
</div>
<div class='toggle-button'></div>
<div class='moon-icon-wrapper'>
<div class="iconify moon-icon" data-icon="feather-moon" data-inline="false"></div>
</div>
</div>
</label>
function myfunction(e) {
const doc = document.documentElement
doc.classList.toggle("dark-mode");
document.querySelectorAll(".inverted").forEach((result) => {
result.classList.toggle("invert");
});
const img = e.currentTarget.querySelector('img')
const label = e.currentTarget.querySelector('span')
if (doc.classList.contains('dark-mode')) {
img.src = 'sun.png'
label.innerHTML = 'Light mode'
} else {
img.src = 'moon.png'
label.innerHTML = 'Dark mode'
}
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', myfunction);
.dark-mode {
filter: invert(1) hue-rotate(180deg);
}
.invert {
filter: invert(1) hue-rotate(180deg);
}
'
<button class="btn">
<img src='moon.png' alt="" />
<span>Dark mode</span>
</button>

How to reset the progress bar after it ends

I've found this script for a progress bar. It runs smoothly from 100% to 0% after clicking the button.
But how can I reset the progress bar after it hits the 0? I'm planning to use this script in a slideshow and it should be 100% again after it reaches 0.
Hope you can help me in the right direction.
Thnx,
Leon
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
You can reset the progress bar by removing the complete class.
document.querySelector("button.start").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector("button.reset").addEventListener("click", () => {
let className = document.querySelector(".progress").className;
if (className.indexOf(' complete') > -1) {
className = className.substr(0, className.indexOf(' complete'));
document.querySelector(".progress .bar").style.transitionDuration = "0s";
document.querySelector(".progress").className = className;
}
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button class="start">
Start
</button>
<button class="reset">
Reset
</button>
If you want this to be dynamic without any user interaction, you can use setTimeout, set to the same duration used in your animationDuration, within your click event Handler to reset the transition and remove the complete class.
const start = document.querySelector("#start")
const progressBar = document.querySelector(".progress .bar")
const progress = document.querySelector(".progress")
function resetProgressBar(){
progressBar.style.transitionDuration = "10s"
progress.classList.add("complete")
setTimeout(() => {
progress.classList.remove("complete")// <-- remove the class with width:0
progressBar.style.transitionDuration = "0.1s" //<-- Add a very small transitionDuration or none if you prefer
}, 10000)// <-- Set this timeout duration to the same as your transitionDuration
}
start.addEventListener("click", resetProgressBar);
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button id="start">
Start
</button>
For selector .progress .bar, use a listener for event transitionend, because you are using transition rules in css:
The transitionend event is fired when a CSS transition has completed.
Inside this event listener, set transitionDuration to the default value. And in the next step, remove class complete from .progress, which will return the previous width of the progress bar.
document.querySelector("button").addEventListener("click", () => {
document.querySelector(".progress .bar").style.transitionDuration = "10s";
document.querySelector(".progress").className += " complete";
});
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>
Thnx for all your suggestions. I've implemented the last suggestion into my slideshow script.
It is running and it is refreshing after slide change. But somewhere on the ride it stops, I think it's confused when to start the progress bar.
Anyone an idea to make this more solid?
jQuery('.owl-carousel').owlCarousel({
items: 1,
margin: 0,
nav: false,
dots: false,
slideBy: 1,
rewind: false,
autoplay: true,
autoplayTimeout: 5000,
autoplaySpeed: 10000,
loop: true,
animateOut: 'fadeOut',
responsive: false,
mouseDrag: false,
touchDrag: false,
lazyLoadEager: 2
});
jQuery('.owl-carousel').on('changed.owl.carousel', function(event) {
document.querySelector(".progress .bar").style.transitionDuration = "5s";
document.querySelector(".progress").className += " complete";
})
document.querySelector(".progress .bar").addEventListener("transitionend", () => {
document.querySelector(".progress.complete .bar").style.transitionDuration = "5";
document.querySelector(".progress").classList.remove("complete");
});
.progress {
width: 50%;
height: 2em;
border: 1px solid black;
}
.bar {
width: 100%;
background-color: deepskyblue;
color: white;
text-align: center;
line-height: 2em;
transition-property: width;
transition-timing-function: linear;
}
.progress.complete .bar {
width: 0%;
}
button {
margin-top: 1em;
}
<div class="progress">
<div class="bar">Loading...</div>
</div>
<button>
Start
</button>

Text inside a button is not acting like part of the button?

Soon I'm releasing an album, so I decided to make a promo website for it. The website will be very simple: basically a list of buttons, each with the title of a song and a play button for playing a preview of that song. Also, when any button is clicked I want a popup to open. I'm pretty unexperienced, but I've managed to achieve all this. The only problem I have is that when I click on the title of any song in a button, which is inside a P tagg, the popup doesn't open. It only seems to work if I click on the background of the button, and I don't want that.
Also, something similar happens when de popup does open: I have programmed the popup to close if the user clicks outside the popup. And it works! But it also closes if I click on the text inside the popup.
I'm not sure why this is happening (maybe because of the way I used event listeners in my JS), but I would really appreciate if anyone could tell me how to make the text in the button act like part of the button, and how to avoid that clicking any text in the popup closes it.
I will leave a snippet here with all my code.
var song1 = document.getElementById("SoloYoPreview");
var playbutton1 = document.getElementById("playbutton1");
var button1 = document.getElementById("button1");
var toggle1 = 0;
var song2 = document.getElementById("LaNocheEnteraPreview");
var playbutton2 = document.getElementById("playbutton2");
var button2 = document.getElementById("button2");
var toggle2 = 0;
var song3 = document.getElementById("QueTalSiVamosPreview");
var playbutton3 = document.getElementById("playbutton3");
var button3 = document.getElementById("button3");
var toggle3 = 0;
var song4 = document.getElementById("EsUnRegaloPreview");
var playbutton4 = document.getElementById("playbutton4");
var button4 = document.getElementById("button4");
var toggle4 = 0;
var song5 = document.getElementById("NoMeQuieroMentirPreview");
var playbutton5 = document.getElementById("playbutton5");
var button5 = document.getElementById("button5");
var toggle5 = 0;
function ctrl_song(number, command = "") {
var thissong = window["song"+number];
var thisplaybutton = window["playbutton"+number];
var thisbutton = window["button"+number];
var thistoggle = window["toggle"+number];
if (command == "stop") {
window["toggle"+number] = 2;
thisbutton.style.animationPlayState = "paused";
thisplaybutton.src = "../../Icons/replay_circle_filled_black_48dp.svg";
/*
console.log("stopping");
*/
} else if (command == "pause" || thistoggle == 1 ) {
window["toggle"+number] = 0;
thisbutton.style.animationPlayState = "paused";
thissong.pause();
thisplaybutton.src = "../../Icons/play_circle_filled_black_48dp.svg";
/*
console.log("pausing");
*/
} else if (command == "restart" || thistoggle == 2) {
window["toggle"+number] = 1;
thisbutton.style.animationPlayState = "running";
thissong.currentTime = 0;
thissong.play();
thisplaybutton.src = "../../Icons/pause_circle_filled_black_48dp.svg";
/*
console.log("restarting");
*/
} else if (command == "play" || thistoggle == 0) {
for (var i = 1;; i++) {
try {
window["toggle"+i] = 0;
var fbutton = window["button"+i];
fbutton.style.animationPlayState = "paused";
var fsong = window["song"+i];
fsong.pause();
var fplaybutton = window["playbutton"+i];
fplaybutton.src = "../../Icons/play_circle_filled_black_48dp.svg";
} catch (e) {
break;
}
}
window["toggle"+number] = 1;
thisbutton.style.animationPlayState = "running";
thissong.play();
thisplaybutton.src = "../../Icons/pause_circle_filled_black_48dp.svg";
/*
console.log("playing");
*/
}
}
document.addEventListener("click", function(e){
var sindex = e.target.dataset.sindex;
ctrl_song(sindex);
});
document.addEventListener("animationiteration", function(e) {
var sindexb = e.target.dataset.sindexb;
ctrl_song(sindexb, "stop");
});
var popup = document.getElementById("popupid");
var popupshadow = document.getElementById("popupshadow");
function togglePopup(songtitle = "") {
document.querySelector("#popuptitle").innerHTML = songtitle;
popup.classList.toggle("show");
popupshadow.classList.toggle("show");
}
window.onclick = function(event) {
if (popup.className == "popup show" && event.target !== popup && event.target.className !== "songbuttons") {
togglePopup();
}
}
#import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap');
/* width */
::-webkit-scrollbar {
width: 10px;
}
/* Track */
::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: #888;
}
/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
background: #555;
}
body {
margin: 0px;
background-color: #f1f1f1;
font-family: 'Montserrat', sans-serif;
font-size: 25px;
position: relative;
}
#blurredbanner {
width: auto;
background-image: url("InflamaArtworkBlur.jpg");
background-size: 100%;
background-position: center;
}
#albumcover {
width: 350px;
display: block;
margin-left: auto;
margin-right: auto;
padding-top: 50px;
padding-bottom: 50px;
}
p {
margin-block-start: 0.67em;
color: #111111;
}
h1 {
margin-block-start: 0.67em;
margin-bottom: 0px;
letter-spacing: 15px;
color: #111111;
}
#title {
text-align: center;
}
#links {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
button {
text-decoration: none;
cursor: pointer;
display: flex;
align-items: center;
text-align: center;
position: relative;
border: 1px solid #111111;
background-repeat: no-repeat;
color: #111111;
border-radius: 50px;
font-size: 0.67em;
margin-block-start: 45px;
height: 60px;
width: 50%;
transition: 0.4s;
background-image: linear-gradient( rgba(200,200,200,0.75), rgba(174,174,174,0.75) );
-webkit-animation: progressbar 30s linear;
animation: progressbar 30s linear infinite;
}
button:hover {
transform: translate(0px, -8px);
}
#keyframes progressbar {
0% {
background-size: 0%;
}
100% {
background-size: 100%;
}
}
#button1 {
animation-play-state: paused;
}
#button2 {
animation-play-state: paused;
}
#button3 {
animation-play-state: paused;
}
#button4 {
animation-play-state: paused;
}
#button5 {
animation-play-state: paused;
}
.songtitle {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin-block-start: 0px;
}
.popup {
position: fixed;
z-index: 2;
visibility: hidden;
top: 150%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #ffffffaf;
border-radius: 10px;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
width: 25%;
height: 50%;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
transition: 0.4s;
}
.popup h1 {
}
.popup.show {
visibility: visible;
top: 50%;
width: 75%;
}
.popupshadow {
background-color: #1111118f;
position: fixed;
width: 100%;
height: 100%;
z-index: 1;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
visibility: hidden;
opacity: 0;
transition: 0.6s;
}
.popupshadow.show {
opacity: 1;
visibility: visible;
}
<!DOCTYPE html>
<HEAD>
<TITLE>Inflama by Dherrera</TITLE>
<LINK rel="stylesheet" href="genericpromo.css">
</HEAD>
<BODY>
<DIV class="popupshadow" id="popupshadow"></DIV>
<DIV id="blurredbanner">
<IMG id="albumcover" src="InflamaArtwork.jpg">
</DIV>
<DIV id="title">
<H1>Inflama</H1>
<P>by Dherrera</P>
</DIV>
<DIV class="popup" id="popupid">
<H1 id="popuptitle"></H1>
<P>by Dherrera</P>
</DIV>
<DIV id="links">
<button class="songbuttons" id="button1" data-sindexb="1" onclick="togglePopup('Solo Yo')">
<audio id="SoloYoPreview">
<source src="audio/SoloYoPreview.mp3" type="audio/mpeg">
</audio>
<img id="playbutton1" data-sindex="1" src="../../Icons/play_circle_filled_black_48dp.svg" >
<P class="songtitle">Solo Yo</P>
</button>
<button class="songbuttons" id="button2" data-sindexb="2" onclick="togglePopup('La Noche Entera')">
<audio id="LaNocheEnteraPreview">
<source src="audio/LaNocheEnteraPreview.mp3" type="audio/mpeg">
</audio>
<img id="playbutton2" data-sindex="2" src="../../Icons/play_circle_filled_black_48dp.svg">
<P class="songtitle">La Noche Entera</P>
</button>
<button class="songbuttons" id="button3" data-sindexb="3" onclick="togglePopup('Que Tal Si Vamos')">
<audio id="QueTalSiVamosPreview">
<source src="audio/QueTalSiVamosPreview.mp3" type="audio/mpeg">
</audio>
<img class="playbtns" id="playbutton3" data-sindex="3" src="../../Icons/play_circle_filled_black_48dp.svg">
<P class="songtitle">Que Tal Si Vamos</P>
</button>
<button class="songbuttons" id="button4" data-sindexb="4" onclick="togglePopup('Es Un Regalo')">
<audio id="EsUnRegaloPreview">
<source src="audio/EsUnRegaloPreview.mp3" type="audio/mpeg">
</audio>
<img id="playbutton4" data-sindex="4" src="../../Icons/play_circle_filled_black_48dp.svg">
<P class="songtitle">Es Un Regalo</P>
</button>
<button class="songbuttons" id="button5" data-sindexb="5" onclick="togglePopup('No Me Quiero Mentir')">
<audio id="NoMeQuieroMentirPreview">
<source src="audio/NoMeQuieroMentirPreview.mp3" type="audio/mpeg">
</audio>
<img id="playbutton5" data-sindex="5" src="../../Icons/play_circle_filled_black_48dp.svg">
<P class="songtitle">No Me Quiero Mentir</P>
</button>
</DIV>
<!--SCRIPT-->
<SCRIPT src="genericpromov2.js"></SCRIPT>
</BODY>
</html>
Thanks in advance!
The only problem I have is that when I click on the title of any song
in a button, which is inside a <p> tag, the popup doesn't open
You need to add this style to your CSS:
.songtitle {
pointer-events: none;
}
This means that if anyone clicks on the <p> inside the <button>, it will be the <button> underneath which registers the click, rather than the <p>.
Further Reading:
https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events

Carousel prev and next button logic does not work

I am trying to a make carousel using pure Javascript. I successfully manage to slide the carousel and have created left and right buttons.
I took my slide functions and added them to the button on-click event-listener, but I have problems when I implement the function on my buttons. It does not behave as expected. My code is below, how can I fix this?
const images = document.getElementById('imgs'); //here
const allImages = document.querySelectorAll('#imgs img');
const leftBtn = document.getElementById('left');
const rightBtn = document.getElementById('right');
let index = 0;
function changeSliderPage() {
const dot = [...document.getElementsByClassName('star')];
index++;
if (index > allImages.length - 1) {
index = 0
}
imgs.style.transform = `translateX(${-index * 500}px)`;
dot.forEach((dot, i) => {
if (i === index) {
dot.classList.add('active')
} else {
dot.classList.remove('active')
}
});
};
allImages.forEach(i => {
const elem = document.createElement('div');
elem.classList.add('star');
document.body.appendChild(elem)
});
rightBtn.onclick = () => {
changeSliderPage(index + 1);
}
leftBtn.onclick = () => {
changeSliderPage(index - 1);
}
let x = setInterval(changeSliderPage, 100000);
images.onmouseover = () => {
clearInterval(x)
}
images.onmouseout = () => {
x = setInterval(changeSliderPage, 2000);
}
*{
box-sizing: border-box;
}
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.carousel {
overflow: hidden;
width: 500px;
height: 500px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, .3);
border-radius: 5px;
}
.image-container {
display: flex;
transition: transform 300ms linear;
transform: translateX(0);
}
img {
width:500px;
height: 500px;
object-fit: cover;
}
.star{
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 10px;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
background-color: #eeeeee;
}
.star.active{
background-color: red;
}
button{
cursor: pointer;
position: relative;
font-size: 18px;
transition: 0.6s ease;
user-select: none;
height: 50px;
width: 40px;
display: flex;
justify-content: center;
align-items: center;
align-content: center;
top: calc(50% - 25px);
}
button:hover {
background-color: rgba(0,0,0,0.8);
};
button.left {
border-radius: 3px 0 0 3px;
right: 0;
}
button.left {
border-radius: 3px 0 0 3px;
left: 0;
}
<button id="left">❮</button>
<button id="right">❯</button>
<div class="carousel">
<div class="image-container" id="imgs" >
<img src="https://images.unsplash.com/photo-1599736375341-51b0a848f3c7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1516026672322-bc52d61a55d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/photo-1573081586928-127ecc7948b0?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
<img src="https://images.unsplash.com/flagged/photo-1572850005109-f4ac7529bf9f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60" alt="">
</div>
</div>
Logic that I use with carousels:
for example you have 4 images:
[1][2][3][4]
I have an animation for sliding every image, I add 5th image which is same as image no 1:
[1][2][3][4][1]
Imagine cursor which shows what image is currently displayed, Ill mark cursor as ! !
So at begin:
[!1!][2][3][4][1]
Now the slider moves on...
[1][!2!][3][4][1]
etc...
It moves to last image:
[1][2][3][4][!1!]
And now it has to move under the hood from last image to first image, but without any animation so the whole change is not visible by user:
[!1!][2][3][4][5]
This way you can get inifinite carousel, just need to check in javascript if current image is last one and you want to slide right -> no animation. Same if you are on 1st image and want to slide left.

Categories