why not close dropdown when click outside in javascript

I have a dropdown in my design that should be deleted when clicked anywhere other than .categories.menu. That is, to lose its show class and close the .categories.menu. At the end of the code I wrote, if this section (categoriesMenu.classList.remove ("show")) is run, it will prevent the dropdown of the show class altogether. so I want to close the menu whenever a user clicks outside the menu.

Thank you in advance for your cooperation.

function toggleClass(elem, className) {
  if (elem.className.indexOf(className) !== -1) {
    elem.className = elem.className.replace(className, '');
  } else {
    elem.className = elem.className.replace(/\s+/g, ' ') + ' ' + className;
  }

  return elem;
}

function toggleDisplay(elem) {
  const curDisplayStyle = elem.style.display;

  if (curDisplayStyle === 'none' || curDisplayStyle === '') {
    elem.style.display = 'block';
  } else {
    elem.style.display = 'none';
  }
}

function toggleMenuDisplay(e) {
  const dropdown = e.currentTarget.parentNode;
  const menu = dropdown.querySelector('.menu');
  toggleClass(menu, 'show');
}

function handleOptionSelected(e) {
  toggleClass(e.target.parentNode, 'show');
  const id = e.target.id;
  const newValue = e.target.textContent + ' ';
  const titleElem = document.querySelector('.dropdown .dropdown--title');
  titleElem.textContent = newValue;
}


const dropdownTitle = document.querySelector('.dropdown .dropdown--title');
const dropdownOptions = document.querySelectorAll('.dropdown .menu.categories a');
dropdownTitle.addEventListener('click', toggleMenuDisplay);
dropdownOptions.forEach(item => item.addEventListener('click', handleOptionSelected));

var categoriesMenu = document.querySelector('.categories.menu');
window.addEventListener('click', function(event) {
var categoriesMenuShow = categoriesMenu.classList.contains("show");
var isClickInsideElement = categoriesMenu.contains(event.target);
  if (isClickInsideElement == categoriesMenuShow ) {
      // categoriesMenu.classList.remove("show")
    }
  });
.dropdown {
  position: relative;
}

.dropdown::before {
  content: "+";
  position: absolute;
  width: 1.5rem;
  height: 1.5rem;
  top: 15px;
  right: 0;
  color: var(--cbl);
}

.dropdown .dropdown--title {
  padding: 0.75rem;
  width: 100%;
  cursor: pointer;
}

.dropdown .menu {
  cursor: pointer;
  max-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: absolute;
  z-index: 12;
  width: 100%;
  top: 45px;
  right: 0;
  background-color: var(--cwh);
  transition: max-height 0.3s;
  -webkit-transition: max-height 0.3s;
  -moz-transition: max-height 0.3s;
  -ms-transition: max-height 0.3s;
  -o-transition: max-height 0.3s;
  box-shadow: 0 3px 20px #ccc;
  -webkit-box-shadow: 0 3px 20px #ccc;
  -moz-box-shadow: 0 3px 20px #ccc;
}

.dropdown .menu.show {
  max-height: 20em !important;
}

.dropdown .menu.show a {
  color: var(--cbl);
  opacity: 1;
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  -ms-transition: all 0.3s;
  -o-transition: all 0.3s;
  transform: translateX(0);
  -webkit-transform: translateX(0);
  -moz-transform: translateX(0);
  -ms-transform: translateX(0);
  -o-transform: translateX(0);
}

.dropdown .menu a {
  padding: 1rem;
  opacity: 0;
  color: var(--cbl);
  transform: translateX(100%);
  -webkit-transform: translateX(100%);
  -moz-transform: translateX(100%);
  -ms-transform: translateX(100%);
  -o-transform: translateX(100%);
}

.dropdown .menu a:nth-child(1) {
  transition-delay: 0.2s;
}

.dropdown .menu a:nth-child(2) {
  transition-delay: 0.15s;
}

.dropdown .menu a:nth-child(3) {
  transition-delay: 0.1s;
}

.dropdown .menu a:nth-child(4) {
  transition-delay: 0.05s;
}

.dropdown .menu a:nth-child(5) {
  transition-delay: 0s;
}

.dropdown .menu a:not(:last-child) {
  border-bottom: 1px solid var(--cblo40);
}

.dropdown .menu a:hover {
  background: rgba(0, 0, 0, 0.2);
}
<div class="dropdown">
  <div class="dropdown--title">Choose category</div>
  <div class="categories menu">
    <a href="#" data-category="[15,16,26,27]" class="clicked">All</a>
    <a href="http://localhost/discount/product-category/other/" data-category="15">Other</a>
    <a href="http://localhost/discount/product-category/electronics/" data-category="16">Electronics</a>
    <a href="http://localhost/discount/product-category/sports/" data-category="26">Sports</a>
    <a href="http://localhost/discount/product-category/toys/" data-category="27">Toys &amp; Games</a>
  </div>
</div>

Upvotes: 2

Views: 92

Answers (1)

Vishal Kalansooriya
Vishal Kalansooriya

Reputation: 520

Try this!

function toggleClass(elem, className) {
  if (elem.className.indexOf(className) !== -1) {
    elem.className = elem.className.replace(className, '');
  } else {
    elem.className = elem.className.replace(/\s+/g, ' ') + ' ' + className;
  }

  return elem;
}

function toggleDisplay(elem) {
  const curDisplayStyle = elem.style.display;

  if (curDisplayStyle === 'none' || curDisplayStyle === '') {
    elem.style.display = 'block';
  } else {
    elem.style.display = 'none';
  }
}

function toggleMenuDisplay(e) {
  const dropdown = e.currentTarget.parentNode;
  const menu = dropdown.querySelector('.menu');
  toggleClass(menu, 'show');
}

function handleOptionSelected(e) {
  toggleClass(e.target.parentNode, 'show');
  const id = e.target.id;
  const newValue = e.target.textContent + ' ';
  const titleElem = document.querySelector('.dropdown .dropdown--title');
  titleElem.textContent = newValue;
}


const dropdownTitle = document.querySelector('.dropdown .dropdown--title');
const dropdownOptions = document.querySelectorAll('.dropdown .menu.categories a');
dropdownTitle.addEventListener('click', toggleMenuDisplay);
dropdownOptions.forEach(item => item.addEventListener('click', handleOptionSelected));

var categoriesMenu = document.querySelector('.categories.menu');
window.addEventListener('click', function(event) {
  var categoriesMenuShow = categoriesMenu.classList.contains("show");
  var isClickInsideElement = categoriesMenu.contains(event.target);
  if (isClickInsideElement == categoriesMenuShow ) {
    // categoriesMenu.classList.remove("show")
  }
});





//newly added code to determine outside clicks
var ignoreClickOnMeElement = document.getElementById('dropdown');

document.addEventListener('click', function(event) {
  var isClickInsideElement = ignoreClickOnMeElement.contains(event.target);
  if (!isClickInsideElement) {
      categoriesMenu.classList.remove("show");
  }
});
.dropdown {
  position: relative;
}

.dropdown::before {
  content: "+";
  position: absolute;
  width: 1.5rem;
  height: 1.5rem;
  top: 15px;
  right: 0;
  color: var(--cbl);
}

.dropdown .dropdown--title {
  padding: 0.75rem;
  width: 100%;
  cursor: pointer;
}

.dropdown .menu {
  cursor: pointer;
  max-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  position: absolute;
  z-index: 12;
  width: 100%;
  top: 45px;
  right: 0;
  background-color: var(--cwh);
  transition: max-height 0.3s;
  -webkit-transition: max-height 0.3s;
  -moz-transition: max-height 0.3s;
  -ms-transition: max-height 0.3s;
  -o-transition: max-height 0.3s;
  box-shadow: 0 3px 20px #ccc;
  -webkit-box-shadow: 0 3px 20px #ccc;
  -moz-box-shadow: 0 3px 20px #ccc;
}

.dropdown .menu.show {
  max-height: 20em !important;
}

.dropdown .menu.show a {
  color: var(--cbl);
  opacity: 1;
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  -ms-transition: all 0.3s;
  -o-transition: all 0.3s;
  transform: translateX(0);
  -webkit-transform: translateX(0);
  -moz-transform: translateX(0);
  -ms-transform: translateX(0);
  -o-transform: translateX(0);
}

.dropdown .menu a {
  padding: 1rem;
  opacity: 0;
  color: var(--cbl);
  transform: translateX(100%);
  -webkit-transform: translateX(100%);
  -moz-transform: translateX(100%);
  -ms-transform: translateX(100%);
  -o-transform: translateX(100%);
}

.dropdown .menu a:nth-child(1) {
  transition-delay: 0.2s;
}

.dropdown .menu a:nth-child(2) {
  transition-delay: 0.15s;
}

.dropdown .menu a:nth-child(3) {
  transition-delay: 0.1s;
}

.dropdown .menu a:nth-child(4) {
  transition-delay: 0.05s;
}

.dropdown .menu a:nth-child(5) {
  transition-delay: 0s;
}

.dropdown .menu a:not(:last-child) {
  border-bottom: 1px solid var(--cblo40);
}

.dropdown .menu a:hover {
  background: rgba(0, 0, 0, 0.2);
}
<div class="dropdown" id="dropdown">
  <div class="dropdown--title">Choose category</div>
  <div class="categories menu">
    <a href="#" data-category="[15,16,26,27]" class="clicked">All</a>
    <a href="http://localhost/discount/product-category/other/" data-category="15">Other</a>
    <a href="http://localhost/discount/product-category/electronics/" data-category="16">Electronics</a>
    <a href="http://localhost/discount/product-category/sports/" data-category="26">Sports</a>
    <a href="http://localhost/discount/product-category/toys/" data-category="27">Toys &amp; Games</a>
  </div>
</div>

Thanks and best regards!

Upvotes: 2

Related Questions