I've created a very basic spreadsheet using an HTML table. It works perfectly, except the user must use the mouse to click on every <td>
in order to edit it. I'm capturing the click event with jQuery and displaying a dialog to edit it. I would like the user to be able to use the arrow keys to navigate to each cell, with the cell css background changing to indicate focus, and clicking the Enter key would trigger the jQuery dialog event. I'm using jQuery 1.9.
Here is a jsfiddle of basically what I have.
How do you save the currently selected cell, so that when you click on a cell with the mouse, and then use the arrow keys, it will navigate from the 'current' cell?
Thanks.
Below is a vanilla JavaScript solution using the onkeydown event and using the previousElementSibling and nextElementSibling properties.
https://jsfiddle.net/rh5aoxsL/
The problem with using tabindex is that you dont get to navigate the way you would in Excel and you can navigate away from the spreadsheet itself.
The HTML
<table>
<tbody>
<tr>
<td id='start'>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
</tr>
<tr>
<td>9</td>
<td>10</td>
<td>11</td>
<td>12</td>
</tr>
<tr>
<td>13</td>
<td>14</td>
<td>15</td>
<td>16</td>
</tr>
</tbody>
</table>
The CSS
table {
border-collapse: collapse;
border: 1px solid black;
}
table td {
border: 1px solid black;
padding: 10px;
text-align: center;
}
The JavaScript
var start = document.getElementById('start');
start.focus();
start.style.backgroundColor = 'green';
start.style.color = 'white';
function dotheneedful(sibling) {
if (sibling != null) {
start.focus();
start.style.backgroundColor = '';
start.style.color = '';
sibling.focus();
sibling.style.backgroundColor = 'green';
sibling.style.color = 'white';
start = sibling;
}
}
document.onkeydown = checkKey;
function checkKey(e) {
e = e || window.event;
if (e.keyCode == '38') {
// up arrow
var idx = start.cellIndex;
var nextrow = start.parentElement.previousElementSibling;
if (nextrow != null) {
var sibling = nextrow.cells[idx];
dotheneedful(sibling);
}
} else if (e.keyCode == '40') {
// down arrow
var idx = start.cellIndex;
var nextrow = start.parentElement.nextElementSibling;
if (nextrow != null) {
var sibling = nextrow.cells[idx];
dotheneedful(sibling);
}
} else if (e.keyCode == '37') {
// left arrow
var sibling = start.previousElementSibling;
dotheneedful(sibling);
} else if (e.keyCode == '39') {
// right arrow
var sibling = start.nextElementSibling;
dotheneedful(sibling);
}
}
I figured it out, based on information I found on a few other posts. I rolled it all together, and the results are perfect.
Note: You have to put a tabindex
attribute on every <td>
to allow navigation.
Here's the jsfiddle. The same code is broken out below.
The HTML:
<table>
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
<th>Col 4</th>
<th>Col 5</th>
<th>Col 6</th>
<th>Col 7</th>
<th>Col 8</th>
</tr>
</thead>
<tbody>
<tr>
<td tabindex="1">1</td>
<td tabindex="2">2</td>
<td tabindex="3">3</td>
<td tabindex="4">4</td>
<td tabindex="5">5</td>
<td tabindex="6">6</td>
<td tabindex="7">7</td>
<td tabindex="8">8</td>
</tr>
<tr>
<td tabindex="10">10</td>
<td tabindex="11">11</td>
<td tabindex="12">12</td>
<td tabindex="13">13</td>
<td tabindex="14">14</td>
<td tabindex="15">15</td>
<td tabindex="16">16</td>
<td tabindex="17">17</td>
</tr>
</tbody>
</table>
<div id="edit">
<form>
<input type="text" id="text" value="To edit..." />
<input type="submit" value="Save" />
</form>
</div>
The CSS:
* {
font-size: 12px;
font-family: 'Helvetica', Arial, Sans-Serif;
box-sizing: border-box;
}
table, th, td {
border-collapse:collapse;
border: solid 1px #ccc;
padding: 10px 20px;
text-align: center;
}
th {
background: #0f4871;
color: #fff;
}
tr:nth-child(2n) {
background: #f1f1f1;
}
td:hover {
color: #fff;
background: #CA293E;
}
td:focus {
background: #f44;
}
.editing {
border: 2px dotted #c9c9c9;
}
#edit {
display: none;
}
The jQuery:
var currCell = $('td').first();
var editing = false;
// User clicks on a cell
$('td').click(function() {
currCell = $(this);
edit();
});
// Show edit box
function edit() {
editing = true;
currCell.toggleClass("editing");
$('#edit').show();
$('#edit #text').val(currCell.html());
$('#edit #text').select();
}
// User saves edits
$('#edit form').submit(function(e) {
editing = false;
e.preventDefault();
// Ajax to update value in database
$.get('#', '', function() {
$('#edit').hide();
currCell.toggleClass("editing");
currCell.html($('#edit #text').val());
currCell.focus();
});
});
// User navigates table using keyboard
$('table').keydown(function (e) {
var c = "";
if (e.which == 39) {
// Right Arrow
c = currCell.next();
} else if (e.which == 37) {
// Left Arrow
c = currCell.prev();
} else if (e.which == 38) {
// Up Arrow
c = currCell.closest('tr').prev().find('td:eq(' +
currCell.index() + ')');
} else if (e.which == 40) {
// Down Arrow
c = currCell.closest('tr').next().find('td:eq(' +
currCell.index() + ')');
} else if (!editing && (e.which == 13 || e.which == 32)) {
// Enter or Spacebar - edit cell
e.preventDefault();
edit();
} else if (!editing && (e.which == 9 && !e.shiftKey)) {
// Tab
e.preventDefault();
c = currCell.next();
} else if (!editing && (e.which == 9 && e.shiftKey)) {
// Shift + Tab
e.preventDefault();
c = currCell.prev();
}
// If we didn't hit a boundary, update the current cell
if (c.length > 0) {
currCell = c;
currCell.focus();
}
});
// User can cancel edit by pressing escape
$('#edit').keydown(function (e) {
if (editing && e.which == 27) {
editing = false;
$('#edit').hide();
currCell.toggleClass("editing");
currCell.focus();
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With