mike-source
mike-source

Reputation: 1015

Make opening 1 div close all other divs of same class (excluding itself) in JS/JQuery?

I'm trying to write JQuery for a set of animated info boxes. Clicking on the title div.info-box__title should open the adjacent div.info-box__content and at the same time close any other open div.info-box__content

Update - should have specified, I also need ALL boxes to close when user clicks outside any .info-box.

Update 2 - Fiddle here: https://jsfiddle.net/q9orfsoy/

The markup is like this:

 <section id="info-box-3" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>

I always struggle with execution order issues with JS. What I have so far are two functions:

Opening:

$('.info-box__title').bind("click touchstart", function() {

    // close the others and open this one
    if($(this).next('.info-box__content').css('display') == 'none') {
        $(this).next('.info-box__content').slideDown();
        $(this).parents('.info-box').addClass('open');
        $(this).parents('.info-box.open').siblings().children('.info-box__title').hide();
    }
});

Closing:

// hide all when click anywhere else in the document
$(document).bind("click touchstart", function(event) {

    // exclude the one that's currently open
    if(!$(event.target).closest('.info-box.open').length){
        $('.info-box__content').slideUp(function(){
            $(this).parents('.info-box').removeClass('open');
        });
    }
});

What this code does is closes all the info-box__content divs when you click outside them. But if you click on another info-box__title it just opens that as well without closing the rest.

(Initially I thought adding a class of .open to the one that's opened would be enough, but I guess I've run into execution order issues?)

What's the best/recommended way to deal with something like this?

Upvotes: 1

Views: 2675

Answers (5)

tkay
tkay

Reputation: 1726

Here is a solution.

 $('.info-box__title').click(function() {
    var sibling = $(this).siblings('.info-box__content');    
    if(!sibling.is(':visible')){
     $('.info-box__content:visible').slideUp();
        sibling.slideDown(); }
    else sibling.slideUp();
 });
$(document).bind("click touchstart", function(e)
{
    var open_content = $(".info-box__content:visible");

    if (!open_content.parent().is(e.target) 
        && open_content.parent().has(e.target).length === 0) 
    {
        open_content.slideUp();
    }
});
.info-box__title{background:grey;}
.info-box__content{
height:100px;
  display:none;
background:red;

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<section id="info-box-3" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>
<section id="info-box-4" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>
<section id="info-box-5" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>

Upvotes: 1

guest271314
guest271314

Reputation: 1

Try utilizing .index() , jsfiddle https://jsfiddle.net/q9orfsoy/1/

var titles = $(".info-box__title");
var content = $(".info-box__content");

titles.on("click touchstart", function(e) {
   if ($(this).next(".info-box__content")
       .is(":visible")) {
      $(this).next(".info-box__content")
      .slideUp()
   } else {
  content.slideUp()
  .eq($(this).index(".info-box__title"))
  .slideDown()  
   }
});
// ALL boxes to close when user clicks outside any `.info-box`
$(document).on("click touchstart", function(e) {
  if ($(e.target).is(".info-box, .info-box *")) {
    return
  }
  else {
    content.slideUp()
  }
})
.info-box__content {
display: none;
}

.info-box {
border: 1px solid black;
padding; 20px;
margin:20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
 <section id="info-box-1" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title 1</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>
 <section id="info-box-2" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title 2</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>
 <section id="info-box-3" class="info-box">
     <div class="centerer">
         <div class="info-box__close"></div>
         <div class="info-box__title">
             <h1>Title 3</h1>
         </div>
         <div class="info-box__content">
             <p>content</p>
         </div>
    </div>
</section>

Upvotes: 2

Ali Sheikhpour
Ali Sheikhpour

Reputation: 11055

Easily slideUp all class while using stop() to slideDown() or slideToggle() target section:

$('.info-box__title').click(function() {
   $('.info-box__content').stop().slideUp();
   $(this).find('.info-box__content').stop().slideDown();
});

$('body').not('.info-box').click(function() {
   $('.info-box__content').stop().slideUp();
});

Upvotes: 0

ferr
ferr

Reputation: 1215

Close all then open the one you want with the this object.

$('.info-box__title').click(function() {
    $('.info-box__content').hide(); //or perform closing action
    $(this).siblings('.info-box__content').show(); //or perform opening action
});

To close when clicking outside of any info box,

$('body').not('.info-box').click(function() {
    $('.info-box__content').hide(); //or perform closing action
});

Upvotes: 1

trentmwillis
trentmwillis

Reputation: 671

You could do:

$(document).bind("click touchstart", function(event) {
  var $openBox = $(event.target).closest('.open');
  $('.info-box__content').not($openBox).slideUp(function(){
    $(this).parents('.info-box').removeClass('open');
  });
});

This will select all boxes other than the one related to the click event.

Bonus explanation

The reason your current solution doesn't work is that your just checking to see if the open box exists, since it does, it then closes all elements with the class `.info-box__content'. Hope that makes sense!

Upvotes: 0

Related Questions