Reputation: 1015
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
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
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
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
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
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