How to prevent Parents Click Event on Child(Grandchild) click event?

Viewed 95

I have a parent div which on click shows one of the child div and again on click on parent will toggle that child div and hide it again. I have a switch toggle inside that child div which will work as checkbox behind the scene. The problem with my code is that when I click on that switch toggle, it fires switch toggle event and also parent click event.

I have tried possible solutions that I found on stack overflow with same kind of questions, but didnot got any success. I tried e.stopPropagation(); on child click event and if(e.target == this) on parent click event but nothing helped. Any help would be appreciated.

Please don't mark it as duplicate as I have tried all given solutions but didn't worked any. Thanks.

$(".parent-block").click(function(e){
  $(this).find("i").toggleClass("fa-chevron-down");
  $(this).find("i").toggleClass("fa-chevron-up");
  $(this).children(".second-child").slideToggle();
})

$("input[type=checkbox]").change(function(e){
  if($(this).is(":checked")){
    $(this).closest('.switch-toggle-div').children('.on-off-label').html("ON");
  } else {
    $(this).closest('.switch-toggle-div').children('.on-off-label').html("OFF");
  }
  // e.stopPropagation();
});
.parent-block {
    border: 1px solid Blue;
    border-radius: 5px;
    margin-bottom: 9px;
    cursor: pointer;
}

.parent-block > div {
    margin: auto 10px;
}

.first-child {
    display: flex;
    justify-content: space-between;
    background: #FFFFFF 0% 0% no-repeat padding-box; 
}

.first-child > p {
    margin: auto 5px;
    padding: 5px;
}
.first-child > i {
    margin: auto 20px;
    color: #D6D6D6;
}

.second-child > p{
    margin: 0 5px;
    padding: 1px 5px;
    color: #A3ADB8;
    font-size: 11px;
}

.grand-child-flex {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 8px;
  padding: 10px 15px 10px 20px;
}

.grand-child-flex > p {
    margin: auto 10px;
    font-size: 12px;
}

.switch {
    position: relative;
    display: inline-block;
    width: 33px;
    height: 16px;
    margin: auto 10px;
}

.switch input { 
    opacity: 0;
    width: 0;
    height: 0;
}

.slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #E4E4E4;
    -webkit-transition: .4s;
    transition: .4s;
}
  
.slider:before {
    position: absolute;
    content: "";
    height: 12px;
    width: 12px;
    left: 3px;
    bottom: 2px;
    background-color: white;
    -webkit-transition: .4s;
    transition: .4s;
}

input:checked + .slider {
    background-color: #21D59B;
}

input:focus + .slider {
    box-shadow: 0 0 1px #21D59B;
}
  
input:checked + .slider:before {
    -webkit-transform: translateX(15px);
    -ms-transform: translateX(15px);
    transform: translateX(15px);
}
  
  /* Rounded sliders */
.slider.round {
    border-radius: 1000px;
}
  
.slider.round:before {
    border-radius: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" 
    integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<div class="parent-block">
  <div class="first-child">
    <p>News</p>
    <i class="fas fa-chevron-down"></i>
  </div>
  
  <div class="second-child" style="display: none;">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
    <div class="grandchild-flex">
      <p>Notifications</p>
      <div class="switch-toggle-div">
        <span class="on-off-label">ON</span>
        <label class="switch">
          <input type="checkbox" checked>
          <span class="slider round"></span>
        </label>
      </div>
    </div>
  </div>
</div>

<div class="parent-block">
  <div class="first-child">
    <p>Alerts</p>
    <i class="fas fa-chevron-down"></i>
  </div>
  
  <div class="second-child" style="display: none;">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
    <div class="grandchild-flex">
      <p>Notifications</p>
      <div class="switch-toggle-div">
        <span class="on-off-label">ON</span>
        <label class="switch">
          <input type="checkbox" checked>
          <span class="slider round"></span>
        </label>
      </div>
    </div>
  </div>
</div>

Demo: jsfiddle

1 Answers

Even if you stop propagation on the checkbox's "change" event, the "click" event that causes the change still propagates to its ancestors.

You can stop propagation of the click event on the <label> (or any ancestor between the checkbox and the parent block):

$('.switch').on('click', function(e) {
  e.stopPropagation();
});

Here's a demonstration:

$(".parent-block").on('click', function() {
  $(this).find("i").toggleClass("fa-chevron-down");
  $(this).find("i").toggleClass("fa-chevron-up");
  $(this).children(".second-child").slideToggle();
})

$("input[type=checkbox]").on('change', function() {
  if ($(this).is(":checked")) {
    $(this).closest('.switch-toggle-div').children('.on-off-label').html("ON");
  } else {
    $(this).closest('.switch-toggle-div').children('.on-off-label').html("OFF");
  }
});

$('.switch').on('click', function(e) {
  e.stopPropagation();
});
.parent-block {
  border: 1px solid Blue;
  border-radius: 5px;
  margin-bottom: 9px;
  cursor: pointer;
}

.parent-block>div {
  margin: auto 10px;
}

.first-child {
  display: flex;
  justify-content: space-between;
  background: #FFFFFF 0% 0% no-repeat padding-box;
}

.first-child>p {
  margin: auto 5px;
  padding: 5px;
}

.first-child>i {
  margin: auto 20px;
  color: #D6D6D6;
}

.second-child>p {
  margin: 0 5px;
  padding: 1px 5px;
  color: #A3ADB8;
  font-size: 11px;
}

.grand-child-flex {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-bottom: 8px;
  padding: 10px 15px 10px 20px;
}

.grand-child-flex>p {
  margin: auto 10px;
  font-size: 12px;
}

.switch {
  position: relative;
  display: inline-block;
  width: 33px;
  height: 16px;
  margin: auto 10px;
}

.switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: #E4E4E4;
  -webkit-transition: .4s;
  transition: .4s;
}

.slider:before {
  position: absolute;
  content: "";
  height: 12px;
  width: 12px;
  left: 3px;
  bottom: 2px;
  background-color: white;
  -webkit-transition: .4s;
  transition: .4s;
}

input:checked+.slider {
  background-color: #21D59B;
}

input:focus+.slider {
  box-shadow: 0 0 1px #21D59B;
}

input:checked+.slider:before {
  -webkit-transform: translateX(15px);
  -ms-transform: translateX(15px);
  transform: translateX(15px);
}


/* Rounded sliders */

.slider.round {
  border-radius: 1000px;
}

.slider.round:before {
  border-radius: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<div class="parent-block">
  <div class="first-child">
    <p>News</p>
    <i class="fas fa-chevron-down"></i>
  </div>

  <div class="second-child" style="display: none;">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
    <div class="grandchild-flex">
      <p>Notifications</p>
      <div class="switch-toggle-div">
        <span class="on-off-label">ON</span>
        <label class="switch">
          <input type="checkbox" checked>
          <span class="slider round"></span>
        </label>
      </div>
    </div>
  </div>
</div>

<div class="parent-block">
  <div class="first-child">
    <p>Alerts</p>
    <i class="fas fa-chevron-down"></i>
  </div>

  <div class="second-child" style="display: none;">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
    <div class="grandchild-flex">
      <p>Notifications</p>
      <div class="switch-toggle-div">
        <span class="on-off-label">ON</span>
        <label class="switch">
          <input type="checkbox" checked>
          <span class="slider round"></span>
        </label>
      </div>
    </div>
  </div>
</div>

Related