1

I want (setting - content) to be closed every time the user clicks on any part of the window except setting - content. but not work this code: (document.querySelector('body').addEventListener('click', function(e){....})and signals an error. How can I do this correctly?

var icon = document.getElementsByClassName("setting--icon");
var panel = document.getElementsByClassName('setting--content');
for (var i = 0; i < icon.length; i++) {
   icon[i].onclick = function(){
    var setClasses = !this.classList.contains('active');
        setClass(icon, 'active', 'remove');
        setClass(panel, 'active', 'remove');
        if (setClasses) {
         this.classList.toggle("active");
        this.nextElementSibling.classList.toggle("active");
       }
   }
}

function setClass(els, className, fnName) {
 for (var i = 0; i < els.length; i++) {
   els[i].classList[fnName](className);
 }
}

document.querySelector('body').addEventListener('click', function(e){
   if (!(event.target == 'setting--content')) {                 panel.classList.remove('active');
    this.nextElementSibling.classList.remove("active");
  }
})
.setting--icon{
  border: 1px solid red;
  width:20px;
  height:20px;
}


.setting--content {
    position: fixed;
    left: 50%;
    top: -150%;
    width: 50%;
    height:20px;
    margin: 0 auto;
    text-align: center;
    transition: 0.3s;
    min-height: 300px;
    padding: 2rem;
    transform: translateX(-50%);
    border:1px solid green;
}

.setting--content.active {
    top: 20%;
}
<form >
  <div class="setting--icon">1</div> 
  <div class="setting--content">
    <input type="text" name="address" id="address" placeholder="search …">
  </div>
</form>

<div>
  <div class="setting--icon">2</div>
  <div class="setting--content"> 
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus explicabo repellendus quos illo eaque vitae, nostrum id accusantium. Cum est fugiat animi molestiae dicta praesentium repellat ipsa iusto dolore perspiciatis?     </p>
  </div>
</div>

1 Answer 1

1

To check which element has clicked, you can use matches method on HTMLElement, in your body click handler you can use it like this:

event.target.matches('.setting--content');

In your snippet, you are toggling the .setting--content by clicking on .setting--icon, so you should check that target is not .setting--icon like this:

event.target.matches('.setting--icon');

in order to above checkings, you should also check that clicked item is not in the .setting--content, you can do it by storing the current active panel in a variable and by using of contains method, check that clicked item is part of the .setting--content or not. like this:

var icon = document.getElementsByClassName("setting--icon");
var panel = document.getElementsByClassName('setting--content');
var activePanel = null;
for (var i = 0; i < icon.length; i++) {
  icon[i].onclick = function() {
    var setClasses = !this.classList.contains('active');
    setClass(icon, 'active', 'remove');
    setClass(panel, 'active', 'remove');
    if (setClasses) {
      this.classList.toggle("active");
      activePanel = this.nextElementSibling;
      activePanel.classList.toggle("active");
    }
  }
}

function setClass(els, className, fnName) {
  for (var i = 0; i < els.length; i++) {
    els[i].classList[fnName](className);
  }
}

document.querySelector('body').addEventListener('click', function(event) {
  if (!event.target.matches('.setting--content') &&
    !event.target.matches('.setting--icon') &&
    activePanel && !activePanel.contains(event.target)) {
    setClass(panel, 'active', 'remove');
    setClass(icon, 'active', 'remove');
  }
})
body {
  min-height: 100vh;
}

.setting--icon {
  border: 1px solid red;
  width: 20px;
  height: 20px;
}

.setting--content {
  position: fixed;
  left: 50%;
  top: -200%;
  width: 50%;
  height: 20px;
  margin: 0 auto;
  text-align: center;
  transition: 0.3s;
  min-height: 300px;
  padding: 2rem;
  transform: translateX(-50%);
  border: 1px solid green;
}

.setting--content.active {
  top: 20%;
}
<form>
  <div class="setting--icon">1</div>
  <div class="setting--content">
    <input type="text" name="address" id="address" placeholder="search …">
  </div>
</form>

<div>
  <div class="setting--icon">2</div>
  <div class="setting--content">
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus explicabo repellendus quos illo eaque vitae, nostrum id accusantium. Cum est fugiat animi molestiae dicta praesentium repellat ipsa iusto dolore perspiciatis? </p>
  </div>
</div>

BTW, since your .setting--content has fixed display, in below example I added style body{ min-height: 100vh; } in order to prevent body collapssed. and also I changed top property on .setting--content from -150% to -200% to run snippet correctly in preview mode.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.