1

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^)

Adam Abrams
  • 107
  • 1
  • 11
  • 1
    jQuery's `.toggle()` event was removed in 1.9. – j08691 May 05 '14 at 16:41
  • Wow! My "Javascript and Jquery" book I've been working off of, which isn't THAT old, gives it as a pretty basic event, so I'm surprised it's been deprecated/removed already. But I will try the other approach(es) below. – Adam Abrams May 05 '14 at 21:51
  • Do you have any additional elements being added by other javascript or something like that. It may be worth inspecting your HTML in your browser to check that nothing is getting injected between `.item` and `.details` – andyface May 06 '14 at 08:40
  • Nope, I've checked and my HTML is intact and unaltered, andyface. I did edit my post to talk about other jscripts that are being loaded... – Adam Abrams May 07 '14 at 04:15
  • Hmm, I guess without seeing the live code it's hard to diagnose quite why the traversing isn't working properly. Would you be able to post a link to your actual site? – andyface May 07 '14 at 10:00
  • Are you limited to not changing the base HTML btw? If so then of course your options are more limited, but if you can, then perhaps using containers like my answer suggests or a data attribute like @lesssugar's answer may be your best option – andyface May 07 '14 at 10:04
  • I ended up using lesssugar's solution below, andyface. I wish the traversing would have worked, since that would be more semantic and not require specific ID's to be added... but what can I say - it worked! As for the page, it's at http://gazeleyandgazeley.com/site/about/the-strategic-planning-process/ . Might still be worth a look to see if anything's happening under the hood that might have interfered with traversal... or anything else. – Adam Abrams May 07 '14 at 16:39
  • Also, if I used a container - sounds like a good approach though I'll leave well enough alone now - then how would I specify the .details div differently? just `next('.details')`? – Adam Abrams May 07 '14 at 16:42

3 Answers3

0

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

andyface
  • 937
  • 1
  • 9
  • 25
  • I've tried and failed to apply your solution, andyface. See my edited post for the deets. – Adam Abrams May 05 '14 at 22:25
  • Did you try using a container class that wraps both the element that you're triggering the action with and the element you want showing? If the issue is to do with using .parent().next() then this may help as you'll not have to worry about element positioning in the DOM – andyface May 06 '14 at 08:37
0

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/

lesssugar
  • 15,486
  • 18
  • 65
  • 115
-2

.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();
Milind Anantwar
  • 81,290
  • 25
  • 94
  • 125
  • 1
    And the `.parent()` of `.titleRow` is `.item`, whose `.next()` element is `.details()`. And what's "incestors"? That sounds dirty. – j08691 May 05 '14 at 16:48
  • Yes, thanks j08691, I was going to point out the same thing... though that is a good alternative method to be aware of. – Adam Abrams May 05 '14 at 22:16