1
votes

I'm trying to create boxes that show text when expanded and hide again when contracted, but I can't figure out how to trigger the events on child elements only when a box is clicked, instead all children of all boxes are affected when any box is clicked.

Here's my code:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">

<style>
.div{
    height: 50px;
    width: 100px;
    background-color: grey;
}

.cont{
}

.expa{
    display:none;
}
</style>

<script src="jquery-1.11.1.js"></script>
</head>

<body>
<div class=div>
    <p class=cont>Caption</p>
    <p class=expa>String to show when expanded and hide when contracted</p>
</div>
<br>
<div class=div>
    <p class=cont>Caption</p>
    <p class=expa>String to show when expanded and hide when contracted</p>
</div>

<script>
$(document).ready(function(){
var contracted = true;
    $(".div").click(function(){
        if(contracted){
            $(this).animate({height:"200px", width:"600px"}, 200);
            $(".cont").css({display: 'none'});
            $(".expa").delay(200).fadeIn(200);
            contracted = false;
        }else{
            $(this).animate({height:"50px", width:"100px"}, 200);
            $(".cont").delay(200).fadeIn(200);
            $(".expa").css({display: 'none'});
            contracted = true;
        };
    });
});
</script>
</body>
</html>

The problem is that clicking any .div element triggers ALL elements of the .cont and .expa classes and not only those specific for the clicked .div.

Search on Stackoverflow and elsewhere only deals with issues with triggering a parent element event by interacting with a child element.

I've fiddled around with .on(), .parent(), .children() and gone through the jQuery documentation without finding anything.

3

3 Answers

4
votes

You need to make the selector relative to what you click on by using (in your case) $(this).find(...). Using something like $(".cont") will select all elements with that class, whereas $(this).find(".cont") will only search descendant elemenents of what you click on. For example:

Change:

$(".cont").css({display: 'none'});
$(".expa").delay(200).fadeIn(200);

to:

$(this).find(".cont").css({display: 'none'});
$(this).find(".expa").delay(200).fadeIn(200);
2
votes
$(".cont").css({display: 'none'});
$(".expa").delay(200).fadeIn(200);

This actually means "take all elements with class "cont" and change css. Then, take all elements with class "expa" and fade it in."

So, if you need to apply actions only on those items which are children to the current you can use the following functionality:

$(this).find(".cont").css({display: 'none'});
$(this).find(".expa").delay(200).fadeIn(200);

It will find elements with such class names within your current div and apply these changes to them.

2
votes

You would have to use the clicked element as the context of your search for the elements you'd like to manipulate as a result of the click event. However, I think you may still end up with some undesired results. I think this is (or closer to) what you intended. Rather than use a global variable contracted, use a localized one for each click candidate, using data attributes:

$(document).ready(function(){
    $(".div").data('contracted', true).click(function(){
        var contracted = $(this).data('contracted');
        if(contracted) {
            $(this).animate({height:"200px", width:"600px"}, 200);
            $(".cont",this).css({display: 'none'});
            $(".expa",this).delay(200).fadeIn(200);
            $(this).data('contracted',false);
        } else {
            $(this).animate({height:"50px", width:"100px"}, 200);
            $(".cont",this).delay(200).fadeIn(200);
            $(".expa",this).css({display: 'none'});
            $(this).data('contracted',true);
        }
    });
});

$(document).ready(function(){
    $(".div").data('contracted', true).click(function(){
        var contracted = $(this).data('contracted');
        if(contracted) {
            $(this).animate({height:"200px", width:"600px"}, 200);
            $(".cont",this).css({display: 'none'});
            $(".expa",this).delay(200).fadeIn(200);
            $(this).data('contracted',false);
        } else {
            $(this).animate({height:"50px", width:"100px"}, 200);
            $(".cont",this).delay(200).fadeIn(200);
            $(".expa",this).css({display: 'none'});
            $(this).data('contracted',true);
        }
    });
});
.div{
    height: 50px;
    width: 100px;
    background-color: grey;
}

.cont{
}

.expa{
    display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class=div>
    <p class=cont>Caption</p>
    <p class=expa>String to show when expanded and hide when contracted</p>
</div>
<br>
<div class=div>
    <p class=cont>Caption</p>
    <p class=expa>String to show when expanded and hide when contracted</p>
</div>