Mark
Mark

Reputation: 783

How to do a toggle between multiple options with jQuery

I've made an little design with circles that expand when clicking on them. I've multiple circles and want to be able to click and expand on one circle at a time and then the other circle closes.

Here's a codeply of my example: https://www.codeply.com/p/7QdDsEF9ul

And here's the jQuery snippet:

$('.product1').click(function () {
$('#product1').toggleClass('expand');
$('.hidden#1').toggleClass('show');

$('.hidden#2').removeClass('show');
$('#product2').removeClass('expand');
});

$('.product2').click(function () {
$('#product2').toggleClass('expand');
$('.hidden#2').toggleClass('show');
});

As you can see this is not going to be very efficient, especially if I add more circles. Is there an easier way of doing this?

Upvotes: 0

Views: 41

Answers (2)

Daniel Brose
Daniel Brose

Reputation: 1403

Get rid of the id and just use the class .product, then itereate through all

$('.product').each(function(i,v){
    console.log({i:i,v:v,'$(this)':$(this)});
    $(this).on('click',function(){
        $(this).toggleClass('expand');
        $(this).find('.hidden').toggleClass('show');
    })
});

In your current html, this is what you said product DOM looks like:

  <div class="col-sm text-center">
    <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
    <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product2">
      <div class="circle" id="product1">
        <h2>Title 1</h2>
        <div class="hidden" id="2"><br>
          <ul class="list-unstyled">
            <li class="list-item"><span class="link">Top Picks</span></li>
            <li class="list-item"><span class="link">By Brand</span></li>
            <li class="list-item"><span class="link">By Price</span></li>
          </ul>
        </div>
      </div>
    </a>
  </div>

By changing just this line:

      <div class="circle" id="product1">

to:

      <div class="circle product">

you can iterate through all and toggle classes for itself and its child '.hidden'

The $(this) keyword has special meaning inside callback functions like .each(), however i also left in the function(i,v) which means function(index,value) so you can even use those, as i showed via console.


Showing only one product circle at a time

I left everything as the simple toggleClass() that you shared above, though if you wanted to be more explicit you can use hasClass() checks, and can also have only one visible product circle at all times by adding this to first line of the click handler:

$('.product.expand').removeClass('expand').find('.hidden').removeClass('show');


Working Snippet/Fiddle

Codeply needs you to create account and doesnt include code inside post in case service goes down in future, so i moved this inside a stackoverflow snippet so you can see working code.

$('.product').each(function(i,v){
        // console.log({i:i,v:v,'$(this)':$(this)});
        $(this).on('click',function(){ 
            // $('.product.expand').removeClass('expand').find('.hidden').removeClass('show');
            $(this).toggleClass('expand');
            $(this).find('.hidden').toggleClass('show');
        })
    });

    // $('.product1').click(function() {
    //   $(this).nextAll('.hidden:first').toggleClass('show');
    // });
a {
	 font-size: 2.25em;
}
 .active {
	 color: #6bd627;
}
 .circle {
	 width: 150px;
	 height: 150px;
	 background-color: #00aae8;
	 border-radius: 50%;
	 justify-content: center;
	 align-items: center;
	 display: flex;
	 transition: all 0.3s ease-in-out;
	 position: absolute;
}
 .circle h2 {
	 color: #fff;
	 font-size: 0.7em;
	 margin-bottom: auto;
	 margin-top: 55px;
}
 .expand {
	 height: 248px !important;
	 background-color: #6bd627 !important;
	 border-top-left-radius: 50%;
	 border-top-right-radius: 50%;
	 border-bottom-left-radius: 0%;
	 border-bottom-right-radius: 0%;
	 transition: all 0.3s ease-in-out;
	 position: absolute;
}
 .hidden {
	 display: none;
	 opacity: 0;
	 transition: all 0.3s ease-in-out;
}
 .show {
	 display: block !important;
	 position: absolute;
	 opacity: 1;
	 transition: all 0.3s ease-in-out;
}
 .link {
	 font-size: 0.5em;
	 color: #000;
}
 ul, ol {
	 margin: 0;
}
 li {
	 margin-bottom: -0.5em;
}
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

<div class="container-fluid s1" style="margin-bottom:400px;">
    <div class="container py-5">
    <div class="row py-5 align-items-end">
        
      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product1">
          <div class="circle product">
            <h2>Title 1</h2>
            <div class="hidden" id="1"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
          		<li class="list-item"><span class="link">By Brand</span></li>
        		<li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>
      
      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product2">
          <div class="circle product">
            <h2>Title 1</h2>
            <div class="hidden" id="2"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
          		<li class="list-item"><span class="link">By Brand</span></li>
        		<li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>
      
      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product1">
          <div class="circle product">
            <h2>Title 1</h2>
            <div class="hidden"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
          		<li class="list-item"><span class="link">By Brand</span></li>
        		<li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>

    </div>
    </div>
  </div>

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371019

Since the div that needs to be shown is a descendant of the .circle which has its class changed when shown, you can avoid having to fiddle with the child div by using the CSS rule .expand div instead. This way, changes to the parent with .expand will be sufficient.

Give all the <a>s a common class, maybe product, and on click, check to see if its child (the .circle) has the expand class or not. If it does, remove .expand from all elements - otherwise, remove expand from all elements but then add it to the .circle child:

$('.product').click(function() {
  const $circle = $(this).children();
  if ($circle.hasClass('expand')) {
    $('.expand').removeClass('expand');
  } else {
    $('.expand').removeClass('expand');
    $circle.addClass('expand');
  }
});
a {
  font-size: 2.25em;
}

.active {
  color: #6bd627;
}

.circle {
  width: 150px;
  height: 150px;
  background-color: #00aae8;
  border-radius: 50%;
  justify-content: center;
  align-items: center;
  display: flex;
  transition: all 0.3s ease-in-out;
  position: absolute;
}

.circle h2 {
  color: #fff;
  font-size: 0.7em;
  margin-bottom: auto;
  margin-top: 55px;
}

.expand {
  height: 248px !important;
  background-color: #6bd627 !important;
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
  border-bottom-left-radius: 0%;
  border-bottom-right-radius: 0%;
  transition: all 0.3s ease-in-out;
  position: absolute;
}

.hidden {
  display: none;
  opacity: 0;
  transition: all 0.3s ease-in-out;
}

.expand div {
  display: block !important;
  position: absolute;
  opacity: 1;
  transition: all 0.3s ease-in-out;
}

.link {
  font-size: 0.5em;
  color: #000;
}

ul,
ol {
  margin: 0;
}

li {
  margin-bottom: -0.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container-fluid s1">
  <div class="container py-5">
    <div class="row py-5 align-items-end">

      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product">
          <div class="circle">
            <h2>Title 1</h2>
            <div class="hidden"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
                <li class="list-item"><span class="link">By Brand</span></li>
                <li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>

      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product">
          <div class="circle">
            <h2>Title 1</h2>
            <div class="hidden" id="2"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
                <li class="list-item"><span class="link">By Brand</span></li>
                <li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>

      <div class="col-sm text-center">
        <img src="https://placehold.it/300x300" class="pb-3 img-fluid" />
        <a href="javascript:void(0)" class="d-flex justify-content-center mt-0 product">
          <div class="circle">
            <h2>Title 1</h2>
            <div class="hidden"><br>
              <ul class="list-unstyled">
                <li class="list-item"><span class="link">Top Picks</span></li>
                <li class="list-item"><span class="link">By Brand</span></li>
                <li class="list-item"><span class="link">By Price</span></li>
              </ul>
            </div>
          </div>
        </a>
      </div>

    </div>
  </div>
</div>

You don't need any IDs or numeric-indexed classes now.

Upvotes: 1

Related Questions