0

I have two div's that I open that kinda belong together, but for programming reasons can't be connected. I simplified the code here because it's a lot of code. This is the basic.

<div id="container">

  <div id="div1">
     <div> when I am clicked I will open div2 </div>
  </div>

  <div id="div2">
     <div> I can be clicked and all the div's stay open </div>
  </div>

</div> 

And this is the connected JavaScript

  $(document).mouseup(function (e) {
    var container = $("#div1");
    if (!container.is(e.target) && container.has(e.target).length === 0) {
      container.hide();
    }
  });

  $(document).mouseup(function (e) {
    var container = $("#div2");
    if (!container.is(e.target) && container.has(e.target).length === 0) {
      container.hide();
    }
  });

Now what I would like to do is when I click outside div1 it should close div1.

When I click on div1 it opens div2.

Currently with the above when I click in div2 it closes div1, because it is not a child of div1. So it should keep div2 opened.

And when I click outside div1 or div2 it should close the two div's.

How can I combine the two JavaScript codes to get the explained behaviour?

Summary of what I try to accomplish:

  1. Click on the div inside div1 will open div2
  2. Click outside div1 or div2 will close both div1 and div2.
  3. In case the div inside div1 is not clicked and one clicks outside div1, it should close div1.
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
Ewald Bos
  • 1,560
  • 1
  • 20
  • 33

3 Answers3

1

Pretty theorical....

But requirements are quite clear. I would do it using .stopPropagation().

e.target is the element clicked. If it is a child of an element having a "concurring handler" on the same event, the handler from the parent will execute. Except if you stop the propagation, which you should look at here.

Having a handler on a top-most parent that say "hide all", will will overcome the handler of the child saying somthing else. So in this case... From the child, you do not want the click (or mouseup... or whatever the event) to propagate to the top parent.

In short: .stopPropagation() will keep the event on the releveant element and you can "not care about" any concurring handler from the parents.

$("#div1").on("click", function(e){
  e.stopPropagation();
  whoAmI(e);
  $("#div2").show();
});

$("#div2").on("click", function(e){
  e.stopPropagation();
  whoAmI(e);
  console.log("I was clicked and #div1 stayed opened.");
});

$("#container").on("click",function(e){
  $("#div1,#div2").hide();
  whoAmI(e);
});

function whoAmI(e){
console.clear();
  console.log( "I'm "+e.target.tagName+" "+((e.target.id=='')? "child" : e.target.id) );
}
#container{
  height:1000px;
}
#div1, #div2{
  border:1px solid red;
  padding:2em;
  margin:3em;
}
#div2{
  display:none;
}
#container>div>div{
  border:1px solid blue;
  padding:0.5em;
  margin:1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="container">

  <div id="div1">
    <div> When I am clicked I will open div2 </div>
    <div> I also do the same. </div>
  </div>

  <div id="div2">
    <div> I can be clicked and all the div's stay open </div>
    <div> I also do the same. </div>
    <div> And me too! </div>
  </div>

</div>
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
  • does the stopPropagation has a herritage, lets say that div2 has multiple elements inside that can be clicked, does one need to repeat the e.stopPropagation(); in each instruction? – Ewald Bos Jan 08 '18 at 23:27
  • 1
    Any element within `div2` (child of `div2`) will be affected by the handler... Unless the child also has a `stopPropagation()`. -- Think about the event being triggered on an element. The browser looks UP to find a handler and applies the last found. You can stop that lookout. That is from the clicked element to its top most parent (`` if nothing stops). – Louys Patrice Bessette Jan 08 '18 at 23:29
  • 1
    Basically, you could say (in human language): I'm a container and I don't listen to my parents handlers anymore (on a specific event or set of events). My childs will llisten to my handlers now. ;) It's like you break the chain. – Louys Patrice Bessette Jan 08 '18 at 23:35
  • 1
    I updated the snippet with a function to make the clicked element obvious in console. – Louys Patrice Bessette Jan 09 '18 at 00:02
1

Using closest() and a common class makes this simpler

$(document).mouseup(function(e) {
  !$(e.target).closest('.content').length &&  $('.content').hide(); 
});

$('#div1').click(function() {
  $('#div2').show();
})
#div2{display:none}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div id="div1" class="content">
    <div> when i am clicked i will open div2 </div>
  </div>
  <div id="div2" class="content">
    <div> i can be clicked and all the div's stay open </div>
  </div>
</div>
charlietfl
  • 170,828
  • 13
  • 121
  • 150
0

I suggest this the code written with jQuery:

$(document).on('click', function (e) {
    if ( e.currentTarget.id == 'div1' ) {
        $("#div2").show();
    } else if ( e.currentTarget.id == 'div2' ) {
        $("#div1").hide();
    } else {
        $("#div1").hide();
        $("#div2").hide();
    }
    return false;
});

or in plain Javascript:

function handleClicks(e) {
    var first = document.getElementById('div1'),
        second = document.getElementById('div2');
    if ( e.currentTarget.id == 'div1' ) {
        second.style.display = 'block';
    } else if ( e.currentTarget.id == 'div2' ) {
        first.style.display = 'none';
    } else {
        first.style.display = 'none';
        second.style.display = 'none';
    }
}
document.body.addEventListener('click', handleClicks, false);

Also check the if-else statements there.

Sergey Sklyar
  • 1,902
  • 1
  • 15
  • 27