Home > database >  Remove class from body when modal is closed with vanilla javascript
Remove class from body when modal is closed with vanilla javascript

Time:11-13

I have multiple modals on my page that open when click on the respective button. When a modal is open it adds the class .has-modal-open to the body to prevent the page from scrolling. The problem is when I close the modal that class doesn't get removed from the body tag. I tried body.classList.remove('has-modal-open'); but for some reason it just doesn't work. I'm looking for a vanilla javascript solution.

Thank you.

  const modal = document.querySelectorAll('.modal');
  const modalOpenButtons = document.querySelectorAll('[data-open-modal]');
  const modalCloseButtons = document.querySelectorAll('[data-close-modal]');
  const body = document.querySelector('body');
  
  for (let i = 0; i < modalOpenButtons.length; i  ) {
    const modalOpenButton = modalOpenButtons[i];
    modalOpenButton.addEventListener('click', e => {
      body.classList.add('has-modal-open');
      const modalDataAttribute = e.target.getAttribute('data-open-modal');
      document.querySelector('.modal[data-open-modal=\''.concat(modalDataAttribute, '\']')).classList.add('modal--is-open');
    });
  }
  
  for (let i = 0; i < modalCloseButtons.length; i  ) {
    body.classList.remove('has-modal-open');
    const modalCloseButton = modalCloseButtons[i];
    modalCloseButton.addEventListener('click', e => {
      e.target.closest('.modal').classList.remove('modal--is-open');
    });
  }
  
  for (let i = 0; i < modal.length; i  ) {
    const modals = modal[i];
    document.addEventListener('keydown', e => {
      if (e.keyCode === 27) {
        modals.classList.remove('modal--is-open')
      }
    })
    modals.addEventListener('click', e => {
      e.target.classList.remove('modal--is-open')
    })
  }
.modal {
  display: none;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  max-height: calc(100% - 48px);
  background: rgba(0, 0, 0, 0.45);
  z-index: 90;
}

.modal__header {
  position: relative;
  border-radius: 4px 4px 0 0;
  background-color: white;
  width: 100%;
  min-height: 60px;
  overflow: auto;
}

.modal__body {
  position: relative;
  width: calc(100% - 48px);
  max-width: 900px;
  max-height: calc(100% - 48px);
  overflow: hidden;
  border-radius: 4px;
  max-height: 700px;
  background: white;
}

.modal__content {
  padding: 0 40px 40px;
  overflow: auto;
  height: 100px;
}

.modal--is-open {
  display: flex;
}

.has-modal-open {
  overflow-y: hidden;
}


.modal__close {
  position: absolute;
  top: 32px;
  right: 12px;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  padding: 0;
}
<button class="button" data-open-modal="open-modal-1">Open modal</button>

<div class="modal" data-open-modal="open-modal-1">
  <div class="modal__body">
    <div class="modal__header">
      <button class="modal__close" data-close-modal>X</button>
    </div>
    <div class="modal__content">
      My modal
    </div>
  </div>
</div>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Your code has 2 problems:

  • body.classList.remove('has-modal-open'); should be called inside the eventListener for the close button, but you call it before.
  • modalOpenButtons = document.querySelectorAll('[data-open-modal]'); selects not only the buttons, but also your modals with the attribute data-open-modal. When you click the close button, the modal gets clicked as well, and so in your case calls the eventListener attached to modalOpenButtons. You should put only the buttons in modalOpenButtons, for example like this:

const modalOpenButtons = document.querySelectorAll('button[data-open-modal]');

I made a snippet here below, where you can see that the class gets added/removed correctly

const modal = document.querySelectorAll('.modal');
  const modalOpenButtons = document.querySelectorAll('button[data-open-modal]');
  const modalCloseButtons = document.querySelectorAll('[data-close-modal]');
  const body = document.querySelector('body');
  
  for (let i = 0; i < modalOpenButtons.length; i  ) {
    const modalOpenButton = modalOpenButtons[i];
    modalOpenButton.addEventListener('click', e => {
      body.classList.add('has-modal-open');
      const modalDataAttribute = e.target.getAttribute('data-open-modal');
      //document.querySelector(`.modal[data-open-modal="${modalDataAttribute}"]`).classList.add('modal--is-open');
      document.querySelector('.modal[data-open-modal=\''.concat(modalDataAttribute, '\']')).classList.add('modal--is-open');
    });
  }
  
  for (let i = 0; i < modalCloseButtons.length; i  ) {
    const modalCloseButton = modalCloseButtons[i];
    modalCloseButton.addEventListener('click', e => {
      body.classList.remove('has-modal-open');
      e.target.closest('.modal').classList.remove('modal--is-open');
    });
  }
  
  for (let i = 0; i < modal.length; i  ) {
    const modals = modal[i];
    document.addEventListener('keydown', e => {
      if (e.keyCode === 27) {
        modals.classList.remove('modal--is-open')
      }
    })
    modals.addEventListener('click', e => {
      e.target.classList.remove('modal--is-open')
    })
  }
.modal {
  display: none;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  max-height: calc(100% - 48px);
  background: rgba(0, 0, 0, 0.45);
  z-index: 90;
}

.modal__header {
  position: relative;
  border-radius: 4px 4px 0 0;
  background-color: white;
  width: 100%;
  min-height: 60px;
  overflow: auto;
}

.modal__body {
  position: relative;
  width: calc(100% - 48px);
  max-width: 900px;
  max-height: calc(100% - 48px);
  overflow: hidden;
  border-radius: 4px;
  max-height: 700px;
  background: white;
}

.modal__content {
  padding: 0 40px 40px;
  overflow: auto;
  height: 100px;
}

.modal--is-open {
  display: flex;
}

.has-modal-open {
  overflow-y: hidden;
}


.modal__close {
  position: absolute;
  top: 32px;
  right: 12px;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  padding: 0;
}
<button class="button" data-open-modal="open-modal-1">Open modal</button>

<div class="modal" data-open-modal="open-modal-1">
  <div class="modal__body">
    <div class="modal__header">
      <button class="modal__close" data-close-modal>X</button>
    </div>
    <div class="modal__content">
      My modal
    </div>
  </div>
</div>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

your error simply says that

"message": "Uncaught TypeError: Cannot read properties of null (reading 'classList')",

which means in your code body is representing null there can be several reasons why this happened one might be that you haven't accessed it in proper way

  • Related