Well letās make my modal code more generic, so that you can give it an element, and a connection between that element and the related modal will be set up.
Ultimately we want to be able to issue the following type of command:
addModal(button);
We can put all of the code in the previous jsfiddle inside of a function:
function addModal(el) {
// all existing scripting code in here
}
The getModalFromButton() function can be make more generic, calling it getModalFromData()
instead.
function getModalFromData(el) {
const modalId = el.getAttribute("data-modal");
return modal = document.getElementById(modalId);
}
function openModal(el) {
getModalFromData(el).classList.add("show");
}
and we can then extract whatās not needed inside of there.
The modalButtons and forEach code can be removed, leaving the rest of the code inside of the function.
function addModal(el) {
...
}
const modalButtons = document.querySelectorAll('.modal-button');
Array.from(modalButtons).forEach(function(el) {
addModal(el);
});
The code that was inside of the forEach function, can have button renamed to el
instead:
function addModal(el) {
...
function openModalHandler(evt) {
openModal(evt.target);
}
...
function closeModalHandler(evt) {
closeModal(upToModal(evt.target));
}
...
const span = getModalFromData(el).querySelector(".close");
el.addEventListener("click", openModalHandler, false);
span.addEventListener("click", closeModalHandler, false);
...
}
And, the window.onclick really should be instead an event on the modal object itself. We can rename isModalBackground to a more appropriate isModalContainer()
instead too.
function isModalContainer(el) {
...
}
...
function modalBackgroundHandler(evt) {
const el = evt.target;
if (isModalContainer(el)) {
closeModal(upToModal(el));
}
}
...
modal.addEventListener("click", modalBackgroundHandler, false);
We can now remove our reliance on the data-modal attribute. Itās useful when setting up a modal, but we donāt want to rely on it whenever we open a modal dialog. We can easily do that by adding a modal reference to the element that opens the modal.
function openModal(el) {
// modal = getModalFromData(el);
el.modalReference.classList.add("show");
}
...
el.modalReference = modal;
const span = modal.querySelector(".close");
Thereās one more thing to make our addModal()
function even more generic, and that is to be able to pass in a modal element separately. That way if the second argument isnāt provided, the data-model attribute will be used instead.
function addModal(el, modal) {
// The two uses of addModal are:
// - addModal(el) with a data-modal reference to the modal
// - addModal(el, modal) to override the data-modal reference
...
if (!modal || !isModalContainer(modal)) {
modal = getModalFromData(el);
}
el.modal = modal;
...
}
And we now have a more generic addModal()
method that we can usefully put in to use. Hereās the full script, which can be seen in action at https://jsfiddle.net/0wstxp81/3/
function addModal(el, modal) {
// The two uses of addModal are:
// - addModal(el) with a data-modal reference to the modal
// - addModal(el, modal) to override the data-modal reference
function getModalFromData(el) {
const modalId = el.getAttribute("data-modal");
return document.getElementById(modalId);
}
function openModal(el) {
el.modal.classList.add("show");
}
function closeModal(modal) {
modal.classList.remove("show");
}
function upToModal(el) {
while (!(el.classList.contains("modal") || el.nodeName === "HTML")) {
el = el.parentNode;
}
return el;
}
function isModalContainer(el) {
return el.classList.contains("modal");
}
function openModalHandler(evt) {
openModal(evt.target);
}
function closeModalHandler(evt) {
closeModal(upToModal(evt.target));
}
function modalBackgroundHandler(evt) {
const el = evt.target;
if (isModalContainer(el)) {
closeModal(upToModal(el));
}
}
if (!modal || !isModalContainer(modal)) {
modal = getModalFromData(el);
}
el.modal = modal;
const span = modal.querySelector(".close");
el.addEventListener("click", openModalHandler, false);
span.addEventListener("click", closeModalHandler, false);
modal.addEventListener("click", modalBackgroundHandler, false);
}
const modalButtons = document.querySelectorAll('.modal-button');
Array.from(modalButtons).forEach(function(el) {
addModal(el);
});