Thursday, March 31, 2011

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.

From stackoverflow
  • 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?

    Matthew Crumley : what about just checking this.next(f).length > 0?
    Peter Boughton : Yes, that makes much more sense; I want to kick myself.
    Peter Boughton : Wait, this is only returning the last two items - so doesn't work if 3 or more items
    grammar31 : If performance degrades try tweaking the selector to do the slicing for you: this.nextAll(f + ':lt(' + Pos + ')')

0 comments:

Post a Comment