How can I use the grandchild of one element to toggle a class on the grandchild of a previous element?

Viewed 116

I've created a fiddle using the same html structure of a plugin I'm trying to edit. There are two 'grandparent' elements containing their ancestors, and I'm trying to use a button contained in one of them to toggle a class on an overlay contained in the other.

I've been trying various jQuery combinations, but so far nothing has worked. This is the one that I feel is most logical, can anyone point out where I'm going wrong?

It might be worth me mentioning that I don't have much flexibility in editing the html structure of the plugin, just the CSS and jQuery.

https://jsfiddle.net/71qdzr9j/4/

jQuery(document).ready(function($) {    
  
  $(".button").click(function() {
    $(this).parentsUntil(".lower-section").previous().find(".overlay").toggleClass("open");
  });
  
});
.wrapper {
  position:relative;
  top:0;
  float:left;
  display:inline-block;
  width:275px;
  background:pink;
  margin-right:24px;
}

.overlay {
  position: absolute !important;
  width: 100% !important;
  height: 100% !important;
  top: 0 !important;
  left: 0 !important;
  background-color: rgba(0,0,0,0.5) !important;
  opacity: 0 !important;
}

.overlay.open {
  opacity:1;
}

.lower-section {
  position:relative;
}

.button {
  position:absolute;
  display:block;
  top:0;
  right:0;
  background:orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<div class="wrapper">

  <a class="upper-section" href="">
    <div class="parent">
      <img class="child" width="275px" height="275px" src="https://i.ibb.co/vjsFfPq/Screenshot-2020-10-03-at-17-30-33.png"/>
      <span class="overlay"></span>
    </div>
  </a>

  <div class="lower-section">
    <div class="lower-section-inner">
      <div class="title">Autumn Trees</div>
      <div class="description">Mist rolling in over the horizion.</div>
      <span class="button">Button</span>
    </div>
  </div>
  
</div>

<div class="wrapper">

  <a class="upper-section" href="">
    <div class="parent">
      <img class="child" width="275px" height="275px" src="https://i.ibb.co/020Lc1f/Screenshot-2020-10-03-at-17-31-09.png"/>
      <span class="overlay"></span>
    </div>
  </a>

  <div class="lower-section">
    <div class="lower-section-inner">
      <div class="title">Ice patterns</div>
      <div class="description">Detail of a frozen landscape.</div>
      <span class="button">Button</span>
    </div>
  </div>
  
</div>

4 Answers

You are nearly there! You are not calling the right jQuery methods to toggle class open on. You need to use parents() and prev() method like this below:

jQuery(document).ready(function($) {    
  $(".button").click(function() {
    $(this).parents(".lower-section").prev().find(".overlay").toggleClass("open");
    });
});

In addition you do not need to important at all. jQuery toggle method will do the job for you.

Working Demo:

jQuery(document).ready(function($) {    
  $(".button").click(function() {
    $(this).parents(".lower-section").prev().find(".overlay").toggleClass("open");
    });
});
.wrapper {
  position: relative;
  top: 0;
  float: left;
  display: inline-block;
  width: 275px;
  background: pink;
  margin-right: 24px;
}

.overlay {
  position: absolute !important;
  width: 100% !important;
  height: 100% !important;
  top: 0 !important;
  left: 0 !important;
  background-color: rgba(0, 0, 0, 0.5) !important;
  opacity: 0;
}

.overlay.open {
  opacity: 1;
}

.lower-section {
  position: relative;
}

.button {
  position: absolute;
  display: block;
  top: 0;
  right: 0;
  background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">

  <a class="upper-section" href="">
    <div class="parent">
      <img class="child" width="275px" height="275px" src="https://i.ibb.co/vjsFfPq/Screenshot-2020-10-03-at-17-30-33.png"/>
      <span class="overlay"></span>
    </div>
  </a>

  <div class="lower-section">
    <div class="lower-section-inner">
      <div class="title">Autumn Trees</div>
      <div class="description">Mist rolling in over the horizion.</div>
      <span class="button">Button</span>
    </div>
  </div>
  
</div>

<div class="wrapper">

  <a class="upper-section" href="">
    <div class="parent">
      <img class="child" width="275px" height="275px" src="https://i.ibb.co/020Lc1f/Screenshot-2020-10-03-at-17-31-09.png"/>
      <span class="overlay"></span>
    </div>
  </a>

  <div class="lower-section">
    <div class="lower-section-inner">
      <div class="title">Ice patterns</div>
      <div class="description">Detail of a frozen landscape.</div>
      <span class="button">Button</span>
    </div>
  </div>
  
</div>


<div class="wrapper">

  <a class="upper-section" href="">
    <div class="parent">
      <img class="child" width="275px" height="275px" src="https://i.ibb.co/vjsFfPq/Screenshot-2020-10-03-at-17-30-33.png"/>
      <span class="overlay"></span>
    </div>
  </a>

  <div class="lower-section">
    <div class="lower-section-inner">
      <div class="title">Autumn Trees</div>
      <div class="description">Mist rolling in over the horizion.</div>
      <span class="button">Button</span>
    </div>
  </div>
  
</div>

You can use closest() in combination with find() to get to your class overlay:

  $(".button").click(function() {
    $(this).closest(".wrapper").find(".overlay").toggleClass("open");
  });

then you need to make sure, that the class "open" is actually executed, using !important

.wrapper .overlay.open {
  opacity:1 !important;
}

or,

in order to avoid use !important as last resource you can remove !important from your .overlay{ opacity: 0 ;}, then it's not needed to use !important in you .overlay.open anymore

see fiddle here: https://jsfiddle.net/8dq6Ljny/1/ with !important

https://jsfiddle.net/8dq6Ljny/2/ without !important

Excited to post my first answer here :-)

Try not to use !important ever! It will cause a lot of mess especially if your code becomes larger. I made my code in vanilla Javascript. JQuery is almost the same logic but just different function names.

My code edit is based on my understanding that you need to change overlay opacity of one picture if you clicked a button under the other picture. However, if you wanted to change opacity of the same picture as the button, then just swap the overlays[1] and overlays[0] in the if {...} statements.

  document.addEventListener("click", function(e) {
    var titles = document.querySelectorAll(".title");
    var overlays = document.querySelectorAll(".overlay");

    var currentTitle = $(e.target).prev().prev().text();
    if (currentTitle === titles[0].innerText) {
      overlays[1].classList.toggle("open");
    }
    if (currentTitle === titles[1].innerText) {
      overlays[0].classList.toggle("open");
    }
  });
.wrapper {
  position: relative;
  top: 0;
  float: left;
  display: inline-block;
  width: 275px;
  background: pink;
  margin-right: 24px;
}

.overlay {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.5) !important;
  opacity: 0;
}

.open {
  opacity: 1;
}

.lower-section {
  position: relative;
}

.button {
  position: absolute;
  display: block;
  top: 0;
  right: 0;
  background: orange;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">

    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="test.css"></link>
  </head>
  <body>
    <!--//////////////////////////////////////////-->
    <div class="wrapper">
      <a class="upper-section" href="">
        <div class="parent">
          <img class="child" width="275px" height="275px" src="https://i.ibb.co/vjsFfPq/Screenshot-2020-10-03-at-17-30-33.png"/>
          <span class="overlay"></span>
        </div>
      </a>

      <div class="lower-section">
        <div class="lower-section-inner">
          <div class="title">Autumn Trees</div>
          <div class="description">Mist rolling in over the horizion.</div>
          <span class="button">Button</span>
        </div>
      </div>
    </div>
    <!--//////////////////////////////////////////-->
    <div class="wrapper">
      <a class="upper-section" href="">
        <div class="parent">
          <img class="child" width="275px" height="275px" src="https://i.ibb.co/020Lc1f/Screenshot-2020-10-03-at-17-31-09.png"/>
          <span class="overlay"></span>
        </div>
      </a>
      <div class="lower-section">
        <div class="lower-section-inner">
          <div class="title">Ice patterns</div>
          <div class="description">Detail of a frozen landscape.</div>
          <span class="button">Button</span>
        </div>
      </div>
    </div>

You're gonna kick yourself, but I think it's because your opacity:1 in .overlay is being overridden but the !important on the opacity:0 in .overlay.open.

Related