Question

I've seen this (apparently) exact same problem addressed here, but the solution is simply not working for me. I can't seem to select the element I wish to show / hide.

I have the following HTML, repeated for several similar items:

<div class="item">
  <div class="titleRow">
    <h3 class="yesterday">Some text</h3>
    <h3 class="today">Some other text</h3>
  </div>
</div> <!-- /item (table) -->

<div class="details">
  <p>A long paragraph of description.</p>
</div>

And this JS:

$('.details').hide();

$('body.page-id-55 .titleRow').toggle(
    function() {

    $(this).parent().next('.details').slideDown();
    $(this).addClass('close');
    },

    function() {
    $(this).parent().next('.details').slideUp();
    $(this).removeClass('close');
    }
)

My understanding is that since .titleRow is being clicked, and .details is the next sibling of its parent (.item), .details should be targeted, and roll down and up when the .titleRow div is clicked.

But in fact nothing happens.

If I change that line to

$('.details').slideDown();

It works, but of course ALL instances of .details roll down and up. I just want the next one after the clicked div to activate.

What am I doing wrong?

UPDATE:

Even with andyface's great suggestion, I still get no action when clicking. I even tried this:

$('body.page-id-55 .titleRow').on('click', function() {

    $details = $(this).parent().next('.details');

    $details.show();

});

To (I would assume) force all .details to simply become visible - but nothing happens then, either.

Possible interference from other JS's on my page?

Still seems like the tree-traversal is the issue, since if I do this:

$('body.page-id-55 .titleRow').on('click', function() {

  $('.details').show();

});

They all appear.

As for potential conflict from other javascripts being loaded, I can at least confirm that my js is the last one being loaded, since I'm using correct WordPress enqueuing method to load it via functions.php. Here's all the js's in the header - my two (one for another page) are last:

<script type='text/javascript' src='http://gazeleyandgazeley.com/site/wp-includes/js/jquery/jquery.js?ver=1.11.0'></script>
<script type='text/javascript' src='http://gazeleyandgazeley.com/site/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1'></script>
<script type='text/javascript' src='http://gazeleyandgazeley.com/site/wp-content/themes/twentythirteen-child/js/sidebarfix.js?ver=9.9.9'></script>
<script type='text/javascript' src='http://gazeleyandgazeley.com/site/wp-content/themes/twentythirteen-child/js/gteam.js?ver=9.9.9'></script>
<script type='text/javascript' src='http://gazeleyandgazeley.com/site/wp-content/themes/twentythirteen-child/js/rolldowns.js?ver=9.9.9'></script>

Would loading it first, or at the end of the document, make a difference? It seems that since the traversing is the only thing "not" working, that it's something about that, not to do with another js conflict... but then again, i don't really know anything. 8^)

Was it helpful?

Solution

Without changing your HTML structure, I would suggest using additional attibute to determine which details to toggle. In the example below I use data-details attribute for title div and id for details div - in order to match proper sections:

HTML

<div class="item">
  <div class="titleRow" data-details="1">
    <h3 class="yesterday">Some text</h3>
    <h3 class="today">Some other text</h3>
  </div>
</div> <!-- /item (table) -->

<div class="details" id="1">
  <p>A long paragraph of description.</p>
</div>

<div class="item">
  <div class="titleRow" data-details="2">
    <h3 class="yesterday">Some text</h3>
    <h3 class="today">Some other text</h3>
  </div>
</div> <!-- /item (table) -->

<div class="details" id="2">
  <p>A long paragraph of description.</p>
</div>

JS

$('.titleRow').click(function() {
    var details_id = $(this).data('details');
    $('div[id="' + details_id + '"]').toggle();
});

PS. You don't need to use hide() for the details divs. Simple CSS display: none will do it.

Working code with comments: http://jsfiddle.net/PhAhu/

OTHER TIPS

Depending on what version of jQuery you're using @j08691's comment is correct, so .toggle() wont do much. You could to do something like this instead:

$('.titleRow').on('click', function(){

    $details = $(this).parent().next('.details');

    if($details.is(':visible')) {

        $details.hide();
    }
    else {

        $details.show();
    }
});

demo: http://jsfiddle.net/andyface/mwLRJ/

Essentially, it's binding a click and then getting the details element, then checking if it's visible and doing the required action.

You could just use slideToggle() on the details section, but I've had issues with toggles not doing what they're supposed to properly, especially if you have another method of closing the content, such as a close button inside the details section, so it's easier to be explicit about what you want it to do and when.

A note of HTML formatting. I usually do stuff like this by wrapping it in a toggle container and then having a trigger and a target, like so:

<div class="toggle-container">
    <div class="parent-div">
        <div class="toggle-trigger">Click to show</div>
        <div>some other stuff</div>
    </div>
    <div>stuff</div>
    <div class="toggle-target" style="display:none;">CONTENT TO SHOW</div>
</div>

This way you can do

$('.toggle-target').on('click', function() {

    var $trigger = $(this),
        $container = $trigger.closest('.toggle-container'),
        $target = $container.find('toggle-target');

    if($target.is(':visible')) {

        $target.show();
        $trigger.text('Click to hide');
    }
    else {

        $target.hide();
        $trigger.text('Click to show');
    }
});

Which gives you a bit more flexibility to have content surrounding the target and trigger and not have to worry about always keeping your details div next to your trigger parent div

.parent() gets the immediate parent of element. for traversing to up through ancestors you need to use .closest() or .parents() .Try this:

 $(this).closest('.item').next().slideDown();

or

 $(this).parents('.item').next().slideDown();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top