Bocochoco
Bocochoco

Reputation: 567

jquery toggle "children"

I can't use .children() here, It won't work since they aren't technically children. With this as my html,

    <p class="l1">A</p>
      <p class="l2">A1</p>
      <p class="l2">A2</p>
      <p class="l2">A3</p>
      <p class="l2">A4</p>
        <p class="l3">A41</p>
      ...

What I'm trying to do is slideToggle all the p.l2 elements that follow p.l1 until it reaches another p.l1. Code folding of sorts, but without nested children. I can't figure out how to do this.

What I've got now doesn't work, seems to hang the browser. There doesn't seem to be a .descendents() function

    $('p.l1').live('click', function()
    {
      var topobj = $(this);
      var done = true;
      while(done)
      {
        if($(topobj).next().hasClass('l2'))
        {
          $(topobj).next().slideToggle(100);
          topobj = $(topobj).next();
        }
        else if($(topobj).next().hasClass('l1'))
          done = false;
      }
    });

This seems to fail because it's given a single element rather than a set of elements. Don't really know how to achieve this...

Upvotes: 0

Views: 966

Answers (5)

David Thomas
David Thomas

Reputation: 253506

There are two obvious ways of achieving your aim, though it'd be far easier with descendent elements.

Option one:

$('p.l1').click(
    function(){
        $('p.l2').slideToggle();
    });

JS Fiddle demo.

Option two:

$('p.l1').click(
    function(){
        $(this).nextUntil('p.l3').slideToggle();
    });

JS Fiddle demo.

Option three:

Trying to make it a little more generic:

$('p[class^="l"]').click(
    function(){
        var thisLevel = parseInt($(this).attr('class').replace('l',''), 10);
        var nxtLevel = (thisLevel + 1);
        $('p.l' + nxtLevel).slideToggle();
    });

JS Fiddle demo.

Option four:

Slightly more generic:

$('p[class^="l"]').click(
    function(){
        var thisLevel = parseInt($(this).attr('class').replace('l',''), 10);
        var nxtLevel = (thisLevel + 1);
        var prvLevel = (thisLevel - 1);
        $('p').nextUntil('p:not("p.l' + nxtLevel + '")').slideToggle();
    });

JS Fiddle demo.

Upvotes: 1

zdyn
zdyn

Reputation: 2183

Sounds like you want nextAll, which lets you grab all the following elements that match a selector. See http://api.jquery.com/nextAll/

Also, I think it's failing because your else if should be:

else if($(topobj).next().hasClass('l3'))
                                 // ^---- l3 instead of l1

(unless there is a typo somewhere given you said you want it to continue until finding another l1, but there isn't)

Also, see what Intelekshual posted in the comments below this about nextUntil. That may be what you want instead.

Upvotes: 1

pimvdb
pimvdb

Reputation: 154968

You have to check for l3 too. Just do !$(topobj).next().hasClass('l1'):

http://jsfiddle.net/zeb5F/

Upvotes: 0

Gonzalo Larralde
Gonzalo Larralde

Reputation: 3541

You have to use nextUntil. It'll find, from the element you've passed, the next elements until it reaches something that matches with the selector that you've passed to it.

$(".l1").click(function() {
    $(this).nextUntil(".l1").toggle()
})

Demo

Please consider using nested <ul> and <li>.

Good luck!

Upvotes: 3

Jon
Jon

Reputation: 437904

nextUntil is the traversal function you need:

$('p.l1).nextUntil('p.l1')

Upvotes: 1

Related Questions