I have a modal box that opens at the click of a button. Everything works fine. However I need another modal box on my page so I duplicated the first modal box but this doesn't open on click button.
What I would like to do is trigger the second modal with the same classes and the same js function in such a way that no more code is added. Is such a thing possible?
Alternatively, how could I activate the second modal by adding the least amount of code?
/* Modal Box Js */
const modal = document.querySelector(".modal");
const trigger = document.querySelector(".trigger");
const closeButton = document.querySelector(".close-button");
function toggleModal() {
modal.classList.toggle("show-modal");
}
function windowOnClick(event) {
if (event.target === modal) {
toggleModal();
}
}
trigger.addEventListener("click", toggleModal);
closeButton.addEventListener("click", toggleModal);
window.addEventListener("click", windowOnClick);
/**********
Modal Box Style
**********/
.trigger {cursor: pointer;}
.modal {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px;
width: 40rem;
border-radius: 6px;
display: flex;
flex-direction: column;
}
.msg-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 12px;
}
.msg-text {
font-size: 14px;
margin-bottom: 6px;
color: #5B616D;
}
.close-button {
float: right;
width: 1.5rem;
line-height: 1.5rem;
text-align: center;
cursor: pointer;
border-radius: 0.25rem;
background-color: lightgray;
align-self: end;
}
.close-button:hover {
background-color: darkgray;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1.0);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<!-- Modal Box 1 -->
<div >Modal Box 1</div>
<div >
<div >
<span >×</span>
<span >Title 1</span>
<span >
“If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it; and this you have the power to revoke at any moment.”
― Marcus Aurelius.
</span>
</div>
</div>
<!-- Modal Box 2 -->
<div >Modal Box 2</div>
<div >
<div >
<span >×</span>
<span >Title 2</span>
<span >
“If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it; and this you have the power to revoke at any moment.”
― Marcus Aurelius.
</span>
</div>
</div>
CodePudding user response:
Your main problem was because of not using NodeList.forEach
to both assign clicks to the desired elements and for not looping the modals to toggle the "open" class.
Here's a variant on your code that uses the aforementioned and the better tool for the job, and that's by using data-*
attribute to reference the desired modal to toggle, namely data-modal
, which can be assigned to any button or element, and accepts the ID selector of the modal to target. So you're not limited to have a specific HTML structure or having to use only one button element-per-modal.
Another issue that's fixed is: never use negative transform in CSS to center your modal content. Use instead margin: auto
inside a flex
parent. Also, add some scrollbars! (See my comments in CSS)
// DOM helpers:
const el = (sel, par) => (par || document).querySelector(sel);
const els = (sel, par) => (par || document).querySelectorAll(sel);
// Task: Modal Box
const elsModals = els(".modal");
const elsModalBtns = els("[data-modal]");
const modalToggle = (id) => {
el(id).classList.toggle("show-modal");
};
const modalsClose = (evt) => {
// Do nothing, click was inside a modal or modal button:
if (evt.target.closest(".modal-content") || evt.target.closest("[data-modal]")) return;
// Else, close all modals:
elsModals.forEach(elMod => elMod.classList.remove("show-modal"));
}
elsModalBtns.forEach(elBtn => {
elBtn.addEventListener("click", () => modalToggle(elBtn.dataset.modal));
});
addEventListener("click", modalsClose);
/*
* Modal Box
*/
.trigger {
cursor: pointer;
}
.modal {
position: fixed;
display: flex;
/* use flex!!! */
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
visibility: hidden;
transform: scale(1.1);
transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;
}
.modal-content {
margin: auto; /* center inside flex parent */
overflow: auto; /* scroll inner content if needed */
max-height: 70vh; /* make it scroll if exceeds this height */
background-color: white;
padding: 20px;
width: 40rem;
border-radius: 6px;
display: flex;
flex-direction: column;
}
.msg-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 12px;
}
.msg-text {
font-size: 14px;
margin-bottom: 6px;
color: #5B616D;
}
.close-button {
text-align: center;
cursor: pointer;
border-radius: 0.25rem;
background-color: lightgray;
align-self: end;
border: 0;
font-size: 1.2rem;
}
.close-button:hover {
background-color: darkgray;
}
.show-modal {
opacity: 1;
visibility: visible;
transform: scale(1.0);
transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;
}
<div data-modal="#modal-lorem">Modal Box 1</div>
<div data-modal="#modal-aurelius">Modal Box 2</div>
<div id="modal-lorem" >
<div >
<button type="button" data-modal="#modal-lorem">×</button>
<span >Title 1</span>
<span >
“Dolor sit amet, consectetur adipisicing elit. Numquam earum debitis architecto, temporibus quod maxime velit, rem ex nam eum ea illum, assumenda nesciunt consectetur quaerat. Accusamus reprehenderit, distinctio et!
”
― Lorem ipsum.
</span>
</div>
</div>
<div id="modal-aurelius" >
<div >
<button type="button" data-modal="#modal-aurelius">×</button>
<span >Title 2</span>
<span >
“he pain is not due to the thing itself, but to your estimate of it; and this you have the power to revoke at any moment.”
― Marcus Aurelius.
</span>
</div>
</div>