'Using arrow keys in a table but having it start from the selected table cell
I am trying to use arrow keys to navigate a table.
The below code works but the problem is that it will only navigate from the last place the arrow key was used. If I click on a cell somewhere else in the table, the arrow key starts from the last position that was moved with the keyboard, not the clicked cell.
This is the code and I assume I need to change the start from the query selector to wherever the mouse last clicked/selected.
Any ideas? Javascript only please, no jquery.
Thank you
function Mouse() {
let start = document.querySelector('.first-element');
const changeStyle = (sibling) => {
if (sibling !== null) {
start.focus();
sibling.focus();
start = sibling;
}
}
const checkKey = (event) => {
event = event || window.event;
const idx = start.cellIndex;
if (event.keyCode === 38) {
// up arrow
const previousRow = start.parentElement.previousElementSibling;
if (previousRow !== null) {
const previousSibling = previousRow.cells[idx];
changeStyle(previousSibling);
}
} else if (event.keyCode === 40) {
// down arrow
const nextRow = start.parentElement.nextElementSibling;
if (nextRow !== null) {
const nextSibling = nextRow.cells[idx];
changeStyle(nextSibling);
}
} else if (event.keyCode === 37) {
// left arrow
const previousSibling = start.previousElementSibling;
changeStyle(previousSibling);
} else if (event.keyCode === 39) {
// right arrow
const nextsibling = start.nextElementSibling;
changeStyle(nextsibling);
}
}
document.onkeydown = checkKey;
}
Solution 1:[1]
I believe that it will help you. move key is [alt] + [shift] + [arrow keys].
const myTable = document.querySelector('#my-Table tbody')
, nbRows = myTable.rows.length
, nbCells = myTable.rows[0].cells.length
, movKey = { ArrowUp : p=>{ p.r = (--p.r +nbRows ) % nbRows }
, ArrowLeft : p=>{ p.c = (--p.c +nbCells) % nbCells }
, ArrowDown : p=>{ p.r = ++p.r % nbRows }
, ArrowRight : p=>{ p.c = ++p.c % nbCells }
}
// get On Focus event on Table elements
myTable
.querySelectorAll('input, [contenteditable=true]')
.forEach(elm=>{elm.onfocus=e=>
{
let sPos = myTable.querySelector('.select')
, tdPos = elm.parentNode
if (sPos) sPos.classList.remove('select')
tdPos.classList.add('select')
}
})
document.onkeydown=e=>
{
let sPos = myTable.querySelector('.select')
, evt = (e==null ? event:e)
, pos = { r: sPos?sPos.parentNode.rowIndex:-1
, c: sPos?sPos.cellIndex:-1
}
if ( sPos // previous pos focus exist...
&& evt.altKey
&& evt.shiftKey // addin shift to control
&& movKey[evt.code] ) // evt.ctrlKey... ?
{
let loop = true
, nxFocus = null
, cell = null
do
{
movKey[evt.code](pos)
cell = myTable.rows[pos.r].cells[pos.c] // possible <td> for new focus...
nxFocus = cell.querySelector('input, [contenteditable=true]') // get focussable element of <td>
if ( nxFocus
&& cell.style.display!=='none'
&& cell.parentNode.style.display!=='none')
{
nxFocus.focus()
loop = false
}
}
while (loop)
}
}
#my-Table {
border-collapse: collapse;
font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
font-size: 14px;
}
#my-Table td {
min-width:20px;
text-align: center;
border: 1px solid grey;
padding: 2px 5px;
white-space: nowrap;
}
.select { background-color: aqua } /* just for the control, delete this line when commissioning the operation */
<table id="my-Table">
<tbody>
<tr>
<td><input placeholder="r0, c0"></td>
<td><div contenteditable="true">Content Editable 1 r0, c1</div></td>
<td style="display: none;"><input placeholder="r0, c2"></td>
<td><div contenteditable="true">Content Editable 2 r0, c3</div></td>
<td><input placeholder="r0, c4"></td>
<td>Not Editable</td>
</tr>
<tr style="display: none;">
<td><input placeholder="r1, c1"></td><td><div contenteditable=" true">Content Editable 1</div></td>
<td style="display: none;"><input value="Input 2"></td>
<td><div contenteditable="true">Content Editable 2</div></td>
<td><input value="Input 3"></td>
<td>Not Editable</td>
</tr>
<tr>
<td><input placeholder="r2, c0"></td>
<td><div contenteditable="true">Content Editable 1</div></td>
<td style="display: none;"><input value="Input 2"></td>
<td><div contenteditable="true">Content Editable 2</div></td>
<td><input value="Input 3"></td>
<td>Not Editable</td>
</tr>
<tr>
<td><input value="Input 1"></td>
<td><div contenteditable="true">Content Editable 1</div></td>
<td style="display: none;"><input value="Input 2"></td>
<td><div contenteditable="true">Content Editable 2</div></td>
<td><input value="Input 3"></td>
<td>Not Editable</td>
</tr>
</tbody>
</table>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Cory R |