I have a HTML table which is created by Ajax
. Rendered markup of this table as below:
<table id="tbl_byKeyboard">
<thead>
<tr>
<th>#</th>
<th>Date</th>
<th>Customer</th>
<th>Discount</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="radio" name="bid" value="122">
</td>
<td>2022-10-01</td>
<td>Customer 01</td>
<td>10%</td>
<td>1000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="123">
</td>
<td>2022-10-01</td>
<td>Customer 02</td>
<td>10%</td>
<td>2000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="124">
</td>
<td>2022-10-01</td>
<td>Customer 03</td>
<td>10%</td>
<td>3000.00</td>
</tr>
</tbody>
</table>
Using this table, basically I want to navigate the table row using 'up' and 'down' arrow key on keyboard. After selecting the right row, the user should be able to check the radio button (within the selected row) by pressing the enter key.
This is my jQuery
code sofar :
$(document).ready(function() {
$(document).on('click', "#tbl_byKeyboard tbody tr", function(e) {
var inp = this.querySelector('input')
if (inp == null) return
if (e.target.tagName != "INPUT") {
inp.checked = !inp.checked
}
$('#tbl_byKeyboard tbody tr').removeClass('active');
$(this).addClass('active');
})
});
$(window).on('keydown', tbl_navigate)
function tbl_navigate(e) {
var $tbl = $('#tbl_byKeyboard');
var $cur = $('.active', $tbl).removeClass('active').first();
if (e.keyCode === 40) { //down
if ($cur.length) {
$cur.next().addClass('active');
} else {
$tbl.children().first().addClass('active');
}
} else if (e.keyCode == 38) { //up
if ($cur.length) {
$cur.prev().addClass('active');
} else {
$tbl.children().last().addClass('active');
}
} else if (e.keyCode == 13) { //enter
var $this = $cur;
var inp = $this.find('input')
if (inp == null) return
if (inp.is(':checked')) {
inp.prop('checked', false);
} else {
inp.prop('checked', true);
$('#tbl_byKeyboard tbody tr').removeClass('active');
$this.addClass('active');
}
}
}
Stack snippet:
$(document).ready(function() {
$(document).on('click', "#tbl_byKeyboard tbody tr", function(e) {
var inp = this.querySelector('input')
if (inp == null) return
if (e.target.tagName != "INPUT") {
inp.checked = !inp.checked
}
$('#tbl_byKeyboard tbody tr').removeClass('active');
$(this).addClass('active');
})
});
$(window).on('keydown', tbl_navigate)
function tbl_navigate(e) {
var $tbl = $('#tbl_byKeyboard');
var $cur = $('.active', $tbl).removeClass('active').first();
if (e.keyCode === 40) { //down
if ($cur.length) {
$cur.next().addClass('active');
} else {
$tbl.children().first().addClass('active');
}
} else if (e.keyCode == 38) { //up
if ($cur.length) {
$cur.prev().addClass('active');
} else {
$tbl.children().last().addClass('active');
}
} else if (e.keyCode == 13) { //enter
var $this = $cur;
var inp = $this.find('input')
if (inp == null) return
if (inp.is(':checked')) {
inp.prop('checked', false);
} else {
inp.prop('checked', true);
$('#tbl_byKeyboard tbody tr').removeClass('active');
$this.addClass('active');
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl_byKeyboard">
<thead>
<tr>
<th>#</th>
<th>Date</th>
<th>Customer</th>
<th>Discount</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="radio" name="bid" value="122">
</td>
<td>2022-10-01</td>
<td>Customer 01</td>
<td>10%</td>
<td>1000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="123">
</td>
<td>2022-10-01</td>
<td>Customer 02</td>
<td>10%</td>
<td>2000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="124">
</td>
<td>2022-10-01</td>
<td>Customer 03</td>
<td>10%</td>
<td>3000.00</td>
</tr>
</tbody>
</table>
My problem is, with this code I can navigate table rows using 'up' and 'down' arrow key, but enter key not working for me.
Hope somebody may help me to figure this out.
CodePudding user response:
The problem is, that at the beginning of your keydown
handler you remove the class active
:
var $cur = $('.active', $tbl).removeClass('active').first();
But in the if
for the Enter
case you don't set that class again, when the input is checked:
if (inp.is(':checked')) {
inp.prop('checked', false);
}
Furthermore the manipulation of the class isn't necessary in the Enter
case - it's only important for the Up
and Down
keys. Therefor you should remove the active
class only in these two cases:
var $cur = $('.active', $tbl).first();
if (e.keyCode === 40) { //down
$cur.removeClass('active');
...
} else if (e.keyCode == 38) { //up
$cur.removeClass('active');
...
}
Because the removal for the Enter
case isn't necessary, you can omit it there:
if (inp.is(':checked')) {
inp.prop('checked', false);
} else {
inp.prop('checked', true);
}
Working example:
i added a small line to focus the first radiobutton for demonstration:
$('#tbl_byKeyboard input[type=radio]').eq(0).focus();
$(document).ready(function() {
$('#tbl_byKeyboard input[type=radio]').eq(0).focus();
$(document).on('click', "#tbl_byKeyboard tbody tr", function(e) {
var inp = this.querySelector('input')
if (inp == null) return
if (e.target.tagName != "INPUT") {
inp.checked = !inp.checked
}
$('#tbl_byKeyboard tbody tr').removeClass('active');
$(this).addClass('active');
})
});
$(window).on('keydown', tbl_navigate)
function tbl_navigate(e) {
var $tbl = $('#tbl_byKeyboard');
var $cur = $('.active', $tbl).first();
if (e.keyCode === 40) { //down
$cur.removeClass('active');
if ($cur.length) {
$cur.next().addClass('active');
} else {
$tbl.children().first().addClass('active');
}
} else if (e.keyCode == 38) { //up
$cur.removeClass('active');
if ($cur.length) {
$cur.prev().addClass('active');
} else {
$tbl.children().last().addClass('active');
}
} else if (e.keyCode == 13) { //enter
var $this = $cur;
var inp = $this.find('input')
if (inp == null) return
if (inp.is(':checked')) {
inp.prop('checked', false);
} else {
inp.prop('checked', true);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="tbl_byKeyboard">
<thead>
<tr>
<th>#</th>
<th>Date</th>
<th>Customer</th>
<th>Discount</th>
<th>Total</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="radio" name="bid" value="122">
</td>
<td>2022-10-01</td>
<td>Customer 01</td>
<td>10%</td>
<td>1000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="123">
</td>
<td>2022-10-01</td>
<td>Customer 02</td>
<td>10%</td>
<td>2000.00</td>
</tr>
<tr>
<td>
<input type="radio" name="bid" value="124">
</td>
<td>2022-10-01</td>
<td>Customer 03</td>
<td>10%</td>
<td>3000.00</td>
</tr>
</tbody>
</table>