Dunnow Dunnow - 2 months ago 12
HTML Question

Skip tr selection using jquery on keydown

So, I have this situation right now:

https://jsfiddle.net/rucjr5cm/



$(function() {
var row = $('.DataList tbody tr.highlight');
var index = row.index();
console.log('current row: ' + index);

function highlight(tableIndex) {
$('.DataList tbody tr').removeClass('highlight');
$('.DataList tbody tr:eq(' + tableIndex + ')').addClass('highlight');
}

$(document).keydown(function(e) {
var currentRow = $('.DataList tbody tr.highlight');

switch (e.which) {
case 38:
var prevRow = currentRow.closest('.DataList tbody tr:not(.Header, .SubHeader, .Total)').prev('tr');
highlight(prevRow.index());
break;
case 40:
var nextRow = currentRow.closest('.DataList tbody tr:not(.Header, .SubHeader, .Total)').next('tr');
highlight(nextRow.index());
break;
}
});
});

.highlight {
background-color: yellow !important;
}
.Header,
.SubHeader,
.Total {
background-color: grey;
}

<script src="https://code.jquery.com/jquery-3.1.1.js" integrity="sha256-16cdPddA6VdVInumRGo6IbivbERE8p7CQR3HzTBuELA=" crossorigin="anonymous"></script>
<table id="data" class="DataList" border="1" cellspacing="1" cellpadding="1">
<tbody>
<tr>
<th>#</th>
<th>header2</th>
<th>header3</th>
<th>header4</th>
<th>header5</th>
</tr>
<tr>
<td>1</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
<tr class="Header">
<td>2</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
<tr class="SubHeader">
<td>3</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
<tr class="highlight">
<td>4</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
<tr>
<td>5</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
<tr class="Total">
<td>6</td>
<td>data</td>
<td>data</td>
<td>data</td>
<td>data</td>
</tr>
</tbody>
</table>





I would like for the highlighted row to skip the grey ones (which are defined by classes and cannot be modified). It would be nice also, if reached the last not greyed out one, to go to the first one (again, not greyed out).

I've tried using the closest + next and prev approach from jQuery too but got nothing out of it either.

I've never used the closest and next / prev approach and I'm certainly doing something wrong, could someone provide any help with it?

Thanks so much!

Answer

I would make use of the nextAll and prevAll functions:

var rows = $('.DataList tbody tr');   // cache this for better performance

function highlight(row) {
  // changed to use the cached object
  rows.removeClass('highlight');
  
  // instead of using the index, you can just pass the object in
  row.addClass('highlight');
}

$(document).keydown(function(e) {
  
  var currentRow = rows.filter('.highlight');   // use filter to get the current highlight

  switch (e.which) {
    case 38:
      e.preventDefault(); // this will stop the page moving when the arrow is pressed

      var prevRows = currentRow.prevAll('tr').not('.Header,.SubHeader,.Total'),  // use prevAll to get all preceding rows and then filter out ones with the classes,
          prevRow;
      
      if (prevRows.length) {
        // test if there is a matching row and then highlight it
        prevRow = prevRows.eq(0);
      } else {
        // no matching so start from the end 
        prevRow = currentRow.nextAll('tr').not('.Header,.SubHeader,.Total').last(); 
      }
      
      highlight(prevRow); // no need to figure out the index.  but if you want you would do rows.index(prevRow); - gets the index with regards to all rows
      break;

    case 40:
      e.preventDefault(); // this will stop the page moving when the arrow is pressed
      var nextRows = currentRow.nextAll('tr').not('.Header,.SubHeader,.Total'),  // same as above but next
          nextRow; 
      
      if (nextRows.length) {
        nextRow = nextRows.eq(0);
      } else {
        nextRow = currentRow.prevAll('tr').not('.Header,.SubHeader,.Total').last();  
        // no matching so start from the beginning 
      }
      
      highlight(nextRow);
      break;
  }
});
.highlight {
  background-color: yellow !important;
}

.Header,
.SubHeader,
.Total {
  background-color: grey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="data" class="DataList" border="1" cellspacing="1" cellpadding="1">
  <thead>               <!-- put header into a thead so it's not included in highlighting -->
    <tr>
      <th>#</th>
      <th>header2</th>
      <th>header3</th>
      <th>header4</th>
      <th>header5</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>1</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
    <tr class="Header">
      <td>2</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
    <tr class="SubHeader">
      <td>3</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
    <tr class="highlight">
      <td>4</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
    <tr>
      <td>5</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
    <tr class="Total">
      <td>6</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
      <td>data</td>
    </tr>
  </tbody>
</table>

With closest in your original answer - it is traversing through the ancestors (parents) rather than across the siblings