Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery - suggestions for a "nextWhile" traversion?

jQuery currently has .next(filter) and .nextAll(filter) but I need something that fits in the middle of these - effectively, a .nextWhile(filter) that repeatedly does next until the filter is no longer true, then stops (rather than continuing to the end).

To demonstrate this, the following is some simplified HTML - (in reality, it is dynamically generated, random order/data, more columns, proper class names, and so on).

<table>
    <thead>
        <tr>
            <th>...</th>
        </tr>
    </thead>
    <tbody>

        <tr class="x"><td>a <button>Show/Hide</button></td></tr>
            <tr class="x y"><td>a1</td></tr>
            <tr class="x y"><td>a2</td></tr>

        <tr class="z"><td>b</td></tr>

        <tr class="z"><td>c</td></tr>

        <tr class="x"><td>d <button>Show/Hide</button></td></tr>
            <tr class="x y"><td>d1</td></tr>
            <tr class="x y"><td>d2</td></tr>
            <tr class="x y"><td>d3</td></tr>

        <tr class="z"><td>e</td></tr>

        <tr class="x"><td>f</td></tr>

        <tr class="x"><td>g <button>Show/Hide</button></td></tr>
            <tr class="x y"><td>g1</td></tr>
            <tr class="x y"><td>g2</td></tr>

    </tbody>
</table>

And against this some JavaScript is run:

<script type="text/javascript">
    var $j = jQuery.noConflict();

    $j().ready(init);

    function init()
    {
        $j('tr.y').hide();
        $j('tr.x button').click( toggleRelated );
    }

    function toggleRelated()
    {
        // Only toggles one row
        // $j(this).parents('tr').next('.y').toggle();

        // Toggles unrelated ones also
        $j(this).parents('tr').nextAll('.y').toggle();

        // Not currently a jQuery construct
        // $j(this).parents('tr').nextWhile('.y').toggle();
    }

</script>

Is there an easy way to implement this nextWhile construct?

Ideally this needs to be achieved without modifying the current HTML.

like image 779
Peter Boughton Avatar asked Feb 12 '09 13:02

Peter Boughton


2 Answers

In jQuery you can create nextWhile() equivalent using nextUntil() method and :not selector. Simply put, while (condition is true) { do something } is same as saying until (condition is false) { do something }.

Consider this trick example where you are required to select all .child elements that follow the first .parent:

<ul id="test">
  <li class="parent"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="divider"></li>
  <li class="parent"></li>
  <li class="child"></li>
  <li class="child"></li>
  <li class="child"></li>
</ul>

The following code is roughly equivalent to .nextWhile(".child") and selects the three .child elements:

$("#test .parent:first").nextUntil(":not(.child)");
like image 142
Salman A Avatar answered Oct 07 '22 18:10

Salman A


UPDATE: Gave up on the recursion idea and decided to count and slice (see last example).

Initial Attempt:
This code is buggy - it only returns the last two items, so doesn't work for 3+ items.

jQuery.fn.nextWhile = function(f)
{
    if( this.next(f).html() )
    {
        return this.next(f).nextWhile(f).andSelf();
    }
    else
    {
        return this;
    }
};


Current Version:

jQuery.fn.nextWhile = function(f)
{
    var Next = this.next(f);
    var Pos = 0;

    while( Next.length > 0 )
    {
        Pos++;
        Next = Next.next(f);
    }

    return this.nextAll(f).slice(0,Pos);
}

This appears to work fine, but I'm not sure if there are any performance penalties to selecting everything and then slicing only a handful from it?

like image 40
Peter Boughton Avatar answered Oct 07 '22 18:10

Peter Boughton