Search code examples
javascriptjqueryjquery-selectorstraversal

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.


Solution

  • 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)");