0

The Issue
I'm looking to implement a flexible javascript solution to opening and closing multiple modal windows on the same page.

I have found way to open multiple modal windows in such a manner, but I can't for the life of me figure out how to close them by the click of a button or by clicking outside of the modal window itself.

Here is my javascript code:

var openModal = document.getElementsByClassName("open-modal");

for (var i = 0; i < openModal.length; i++) {
    var thisOpenModal = openModal[i];

    thisOpenModal.addEventListener("click", function() {
        var modal = document.getElementById(this.dataset.modal);
        modal.style.display = "block";

    }, false);
}

(I didn't write this code myself, it's an edited copy of "pgk's" answer over on this page: Opening multiple modal boxes on one page)

I trigger the modal windows by adding the 'open-modal' class to my "buttons" and I use 'data-modal' in relation to the id's of the modal windows:

<div class="featurette-wrap featurette--anchor open-modal" data-modal="modal-microsoft-account">
   Opprett konto
</div>


The button above triggers the modal window with the id of modal-microsoft-account:

<div class="modal" id="modal-microsoft-account">
    Microsoft-konto
</div>


So my question is:
How can I implement a way to close a modal window once it's opened?


I've tried doing this, but I can't get it to work (from W3schools):

// When the user clicks on <span> (x), close the modal
    closeModal.onclick = function() {
        modal.style.display = "none";
    }

// When the user clicks anywhere outside of the modal, close it
    window.onclick = function(event) {
        if (event.target == modal) {
            modal.style.display = "none";
        }
    }
kheembo
  • 79
  • 10

2 Answers2

1

It's better to use event listeners to track actions on elements as I've done below;

also, making use of the setAttribute function when setting styles with Javascript ensures that every other style assigned to that element is overridden and the style you are setting always applies (except in cases where another style is set to be important)

var openModal = document.getElementsByClassName("open-modal");

for (var i = 0; i < openModal.length; i++) {
  var thisOpenModal = openModal[i];
  var targetModal = thisOpenModal.getAttribute('data-modal')
  //get the id of the modal to open based on thisOpenModal
  var thisTargetModal = document.getElementById(targetModal)
  //get element

  thisOpenModal.addEventListener("click", function(event) {
    thisTargetModal.setAttribute('style', "display:block;")
    //code to open modal on click of div with id=""
  }, false);


  // When the user clicks on <span> (x), close the modal
  var closeModal = document.querySelector('#' + thisTargetModal.id, "span");

  //code to listen to click event and change block style attribute to none on click
  closeModal.addEventListener("click", function() {
    thisTargetModal.setAttribute('style', "display:none;")
  }, false)


  // When the user clicks anywhere on the modal div, close it
  window.addEventListener("click", function(event) {
    //code to listen to click event on window and change block style attribute to none
    if (event.target == targetModal) {
      thisTargetModal.setAttribute('style', "display:none;")
    }
  })

}
<div class="featurette-wrap featurette--anchor open-modal" data-modal="modal-microsoft-account">
  Opprett konto
</div>

<div class="modal" id="modal-microsoft-account" style="display:none;">
  <p>Microsoft-konto </p>
  <p>
    <span id="close-modal">
    x
</span>
  </p>
</div>
dqve
  • 646
  • 6
  • 18
  • Thank you for your explanatory answer dqve This seems to be a good working solution, only I would have to duplicate this approach for every modal window on my page because the id of the modal window is stated explicitly. Say I have three modal windows, I would have to make a js-file for each. I am looking for a way to get around that. – kheembo May 10 '20 at 14:21
  • Okay, no problem @kimnthorstensen, I just edited the code to accommodate multiple modals, try this out instead. – dqve May 10 '20 at 16:02
  • 1
    You sir are a legend! Works like a charm Thank you so much for your help – kheembo May 10 '20 at 17:17
  • You're welcome, I'm glad I could help, in case of any further tweaks though, just leave a comment – dqve May 10 '20 at 17:20
  • Oh, actually it seems that I am only able to open one (the same) modal window even though my two buttons point to different ones So both buttons work, but they both lead me to the same modal window, even though they have different 'data-modal' values relative to the ID's of the modal windows. Do you know what could be causing this behaviour? Here's the page I'm working on: https://bogacraft.no/bli-med/ – kheembo May 10 '20 at 17:54
1

So I actually ended up finding a solution that did exactly what I was looking for over at W3Schools forum: http://w3schools.invisionzone.com/topic/55976-multiple-modal-boxes-on-webpage/

This did the trick :

// Get the modal
var modal = document.getElementsByClassName("modal");

// Get the button that opens the modal
var openModal = document.getElementsByClassName("open-modal");

// Get the <span> element that closes the modal
var closeModal = document.getElementsByClassName("modal__close");

// When the user clicks the button, open the modal
function setDataIndex() {
    for (i = 0; i < openModal.length; i++) {
        openModal[i].setAttribute('data-index', i);
        modal[i].setAttribute('data-index', i);
        closeModal[i].setAttribute('data-index', i);
    }
}

for (i = 0; i < openModal.length; i++) {
    openModal[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modal[ElementIndex].style.display = "block";
    };

    // When the user clicks on <span> (x), close the modal
    closeModal[i].onclick = function() {
        var ElementIndex = this.getAttribute('data-index');
        modal[ElementIndex].style.display = "none";
    };

}

window.onload = function() {
    setDataIndex();
};

window.onclick = function(event) {
    if (event.target === modal[event.target.getAttribute('data-index')]) {
        modal[event.target.getAttribute('data-index')].style.display = "none";
    }
};
kheembo
  • 79
  • 10