black
black

Reputation: 723

How to hide child element clicking outside dynamically?

I can hide child element with add every child element this code:

window.addEventListener('mouseup', function(event){
let children = parent[0].children[0]
if (event.target != children && event.target.parentNode != children){
    children.style.display = 'none';
  }
});

But how can hide child ul element clicking outside child ul element(with for loop or something else) without add this code every child element?

In this code I show child ul element when clicking parent li element

var parent = document.querySelectorAll('body > ul > li');

parent[0].addEventListener('click', function () {
  parent[0].children[0].style.display = 'block';
});

parent[1].addEventListener('click', function () {
  parent[1].children[0].style.display = 'block';
});

parent[2].addEventListener('click', function () {
  parent[2].children[0].style.display = 'block';
});

window.addEventListener('mouseup', function(event){
  let children = parent[0].children[0]
	if (event.target != children && event.target.parentNode != children){
        children.style.display = 'none';
    }
});
ul > li > ul {
  display: none;
}

ul, li {
  width: max-content;
}
<ul>
  <li>parent1
    <ul>
      <li>child1</li>
    </ul>
  </li>
  <li>parent2
    <ul>
      <li>child2</li>
    </ul>
  </li>
  <li>parent3
    <ul>
      <li>child3</li>
    </ul>
  </li>
</ul>

Thanks

Upvotes: 0

Views: 354

Answers (2)

gagan
gagan

Reputation: 269

If I understand your problem: User clicks on any of the child elements, there should not be any change in the child state (hide). You can use the below code (I am assuming that you are using ES5 only). If you want to hide the child elements on parent click, then remove the isParentClick() method.

    var parent = document.querySelectorAll('body > ul > li');
    var len = parent.length;
    for(var i=0;i<len;i++){
      	parent[i].addEventListener('click', function (event) {
        if(event.target !== event.currentTarget.children[0].children[0]){
            if(event.currentTarget.children[0].style.display === 'block'){
              event.currentTarget.children[0].style.display = 'none';
            } else {
              event.currentTarget.children[0].style.display = 'block';
            }
         }
            
    	});
      }
    
    window.addEventListener('mouseup', function(event){  
      if(isParentClick()){
      	return false;
      }
      
      if(isChildClick(event)){
      	return false;
      }
      for(var i=0;i<len;i++){
      	parent[i].children[0].style.display = 'none';
      }
    });
    
    function isParentClick(){
      for(var i=0;i<len;i++){
      	if(parent[i] === event.target){
         return true;
        }
      }
      return false;
    }
    
    function isChildClick(event){
      for(var i=0;i<len;i++){
      	if(parent[i].children[0].children[0] === event.target){
         return true;
        }
      }
      return false;
    }
ul > li > ul {
  display: none;
}

ul, li {
  width: max-content;
}
<ul>
  <li>parent1
    <ul>
      <li>child1</li>
    </ul>
  </li>
  <li>parent2
    <ul>
      <li>child2</li>
    </ul>
  </li>
  <li>parent3
    <ul>
      <li>child3</li>
    </ul>
  </li>
</ul>

Upvotes: 1

brk
brk

Reputation: 50291

You can use document.querySelectorAll instead of targeting individual elements Since to display the child the click will be on li so again do a querySelector and select ul and add the style.

Note use of stopPropagation.There is another event attached to body so that any click on body will hide the child. The usage of stopPropagation is to prevent the event from bubling phase the click on li and click on body both will happen simultaneously.

The body is bordered in red

var parent = document.querySelectorAll('body > ul > li');

parent.forEach(function(item) {
  item.addEventListener('click', function(e) {
    e.stopPropagation()
    
    item.querySelector('ul').style.display = 'block';
  })
  document.body.addEventListener('click', function(e) {
    document.querySelectorAll('.parent').forEach(function(item) {
      item.querySelector('ul').style.display = 'none'
    })
  })
})
ul>li>ul {
  display: none;
}

ul,
li {
  width: max-content;
}

body {
  border: 1px solid red;
}
<ul>
  <li class='parent'>parent1
    <ul>
      <li>child1</li>
    </ul>
  </li>
  <li class='parent'>parent2
    <ul>
      <li>child2</li>
    </ul>
  </li>
  <li class='parent'>parent3
    <ul>
      <li>child3</li>
    </ul>
  </li>
</ul>

Upvotes: 1

Related Questions