PDA

View Full Version : Using the up and down arrow keys to select a table row



jason_kelly
07-25-2013, 01:38 AM
Hi Guruís

I need the help of an expert from this forum on my question below as it is well beyond the level of knowledge that I have for programming in JavaScript.

Given the existing JavaScript coding below, how can I piggy back and add onto the existing coding so as to add functionality for a user to use their up and down arrow keys to scroll through the table, while they are scrolling through (btw the header column exempt) it would highlight the selected row and change its row color.

A point to note that if an existing table row is selected, and I hit my up or down arrow key, it would just move to and highlight the previous and next row. Some logic here is that I am guessing that one would need to find the row index to do this. Like I said, it is well beyond what I know how to do.

Much thanks and a huge appreciation for all your help.



<!DOCTYPE html>
<html>
<head>
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(
function() {
var trows = document.getElementById("mstrTable").rows;

for (var t = 1; t < trows.length; ++t) {
trow = trows[t];
trow.className = "normal";
trow.onclick = highlightRow;
}//end for

function highlightRow() {
for ( var t = 1; t < trows.length; ++t ) {
trow = trows[t];
if (trow != this) { trow.className = "normal" }
}//end for

this.className = (this.className == "highlighted")?"normal":"highlighted";
}//end function



}//end function

)();//end script
</script>
</body>
</html>

jscheuer1
07-25-2013, 04:02 AM
There are lots of ways. I would use version 5 events (add/attach event, rather than version 4), but without doing that, here's a way to get it to work:



<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(
function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow;

while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
trow.onclick = highlightRow;
}//end while

function highlightRow(gethighlight) {
gethighlight = gethighlight === true;
var t = trows.length, hrow;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight && trow !== this) { trow.className = 'normal'; }
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true), nextrow;
if(typeof idx === 'number'){
idx += way;
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); }
else if(idx){ return highlightRow.apply(trows[1]); }
return highlightRow.apply(trows[trows.length - 1]);
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]);
}

function processkey(e){
e = e || event;
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}

document.onkeydown = processkey;

}//end function

)();//end script
</script>
</body>
</html>



Here we go with more annotation and converting to version 5 events:


<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();

while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
addEvent(trow, 'click', highlightRow);
}//end while

function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight && trow !== this) { trow.className = 'normal'; }
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true); //gets current index or null if none highlighted
if(typeof idx === 'number'){//there was a highlighted row
idx += way; //increment\decrement the index value
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); } //index is > 0 and a row exists at that index
else if(idx){ return highlightRow.apply(trows[1]); } //index is out of range high, go to first row
return highlightRow.apply(trows[trows.length - 1]); //index is out of range low, go to last row
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]); //none was highlighted - go to 1st if down arrow, last if up arrow
}//end function

function processkey(e){
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}//end function

addEvent(document, 'keydown', processkey);

}/* end function */)();//execute function and end script
</script>
</body>
</html>

jason_kelly
07-25-2013, 02:13 PM
Another flawless post and magnificent work brought to you by John.

Wow! this level of coding to me is like rocket science. (Im not there yet, someday maybe)

Much thanks and appreciation for all your help and support.

You rock!

Thanks John.

jason_kelly
07-25-2013, 02:17 PM
Hi John,

A quick question for you and my apology for neglecting to mention it.

Is there a way, since I will be dealing with some database work in the back end of this code, to some how throw in alert box to let me know which row number I am on (otherwise clicked or scrolled to)? The count should be started from the 1st row after the table headers to however many rows are in the table.

So when I change the selected row, an alert box will popup and let me know as to what row number I am on?

I guess, just to be on the safe side, is there a way to check if the focus is on the table, then do the entire processkey function, as opposed to just assuming the focus will always be on the table?

I also went with your version 5 events example!

Scratching head...

Thanks again.

Jay

jscheuer1
07-25-2013, 03:34 PM
That should be simple. BTW, in case you're interested in more about the differences between version 5 and version 4 events, see:

http://www.dynamicdrive.com/forums/entry.php?255-Version-5-Events

As to an alert, I question whether that's such a great idea. It would be disruptive to have that going off all the time - each time you change the highlighted row. I wiuld think that it might be better to have an element on the page that would show the current row number. But getting the number would be the same in either case. It's actually much simpler without the alert though, that is if with the alert you want the highlight to change first before the alert fires (additions, changes highlighted):


function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight){
if(trow !== this) { trow.className = 'normal'; }
else if(this.className === 'normal') {
(function(t){
alertfunc = function(){
alert('You are now on row #' + t);
};
})(t);
setTimeout(alertfunc, 0);
}
}
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function



And you should add a var declaration at the beginning (fine point, but we're trying to keep everything local to at least the outer function wrap):


<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow, alertfunc,
addEvent = (function(){return w . . .

All that convoluted coding with the timeout and the function being created in an anonymous function within the while loop is to preserve the value of t at the time it's discovered for execution later, after the highlight has actually changed. There's no alert for when there's no row selected, nut that could be added.

If on the other hand we were to add a text input at the beginning of the table:


<body>
<div id="results" class="scrollingdatagrid">
Current Row: <input type="text" id="rownum" value="None" readonly>
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Numb . . .



Then we can instead do (in the highlightRow function):


function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight){
if(trow !== this) { trow.className = 'normal'; }
else if(this.className === 'normal') { rownum.value = t; }
else { rownum.value = rownum.defaultValue; }
}
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function



Which means we need to add rownum as a variable, and a reset for browsers that remember text inputs on reload here:


(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
rownum = document.getElementById('rownum'),
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();

rownum.value = rownum.defaultValue; //reset for browsers that remember input values on reload

while (--t > -1) {
tro . . .



Here's the whole thing:


<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
Current Row: <input type="text" id="rownum" value="None" readonly>
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
rownum = document.getElementById('rownum'),
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();

rownum.value = rownum.defaultValue; //reset for browsers that remember input values on reload

while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
addEvent(trow, 'click', highlightRow);
}//end while

function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight){
if(trow !== this) { trow.className = 'normal'; }
else if(this.className === 'normal') { rownum.value = t; }
else { rownum.value = rownum.defaultValue; }
}
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true); //gets current index or null if none highlighted
if(typeof idx === 'number'){//there was a highlighted row
idx += way; //increment\decrement the index value
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); } //index is > 0 and a row exists at that index
else if(idx){ return highlightRow.apply(trows[1]); } //index is out of range high, go to first row
return highlightRow.apply(trows[trows.length - 1]); //index is out of range low, go to last row
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]); //none was highlighted - go to 1st if down arrow, last if up arrow
}//end function

function processkey(e){
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}//end function

addEvent(document, 'keydown', processkey);
addEvent(window, 'unload', function(){}); //optional, resets the page for browsers that remember the script state on back and forward buttons

}/* end function */)();//execute function and end script
</script>
</body>
</html>



There's one more optional addition with that, at the end. Opera and Firefox, perhaps others, will remember the script state on navigation to the page that uses the back or forward buttons unless you set an unload event for the page, even an empty one. But this is OK as long as you don't mind that, and as long as the page isn't likely to perhaps have different rows due to a database change or something. So, if you don't mind it and the page doesn't require it, you can comment it out.

jason_kelly
07-25-2013, 03:42 PM
Wow!

I appreciate the level of effort and detail that you have gone in breaking down the code for me.

One last thing to bug you for,

The focus should be set on the table before the user presses their up and down arrow keys. As the table itself will be dynamically generated later on.

How can I check to make sure that the focus is set on the table before allowing the user to scroll through the table.

So that when the page is first loaded, nothing should happen, until the user first clicks and sets focus to the table.

This may seem easy to you, I haven't a clue where to start and put something in the code to have this happen.

Much thanks again.

Glad to have you around :)

Where should I send the bill to ? lol

Jay

jscheuer1
07-25-2013, 04:10 PM
Tables do not receive focus. And the table here need not have focus for the arrow key code to work*. It does have to be there though. If the table is being generated server side, it's no problem, the table will be ready before the script is run. If however the table is generated via javascript, it still will be no problem as long as the code we've been playing around with here runs after the javascript code that creates the table has completed it's work.

Alternatively, you could test for the existence of the table before executing the outer wrapper function, which could no longer be anonymous, rather it would need a name.

But before I get into the details on any of that, just how is the table being generated?



*The arrow key code works off of the keydown event of the document, not the table, as many if not all browsers will not register a keydown event on a table. But as I say, the table (and its rows) need to be there before the part of the code that declares them:


<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = tr . . .



is run. Alternatively this could be declared each time it's needed (in case things have changed), and instead of attaching click events to the rows themselves, one click event could be attached to the document, and if it happens to be on the table, have that row be used.

Again, it all depends upon when and how the rows are generated and more importantly, when and how they become a part of the page.

You can 'send the bill' to one of the donate links at the bottom of my posts. But there's no obligation.

jason_kelly
07-25-2013, 06:14 PM
Great insight John.

Thanks very much for making me understand.

Last question, and it would be useful as well to add functionality, where the row number is specified at the top.

If I specify a row number in the top box and click a "go" button, would it be possible to move the row selection to the specified row number in the input box and highlight that row?

How might that work?

Using your latest example, would it be rather difficult to add that functionality, especially if there is alot of rows.

Thanks in advance,

Cheers,

Jay

jscheuer1
07-25-2013, 09:23 PM
At that point a text input isn't the best choice (it perhaps wasn't to begin with, a div or span might have been better). But expecially now because the user could put in a number that's too high, too low, or even something other than a number. A select element seems ideal. It can be populated by the same while loop that assigns the click events to the rows so it will only contain available choices (rows). It's value will reflect the selected row, and when it's changed, the selected row will change (changes/additions highlighted):


<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
Current Row: <select id="rownum">
<option value="0" selected>None</option>
</select>
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>
</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>
<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
rownum = document.getElementById('rownum'),
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();

function option(num){
var o = document.createElement('option');
o.value = num;
rownum.insertBefore(o, rownum.options[1]); //IE 8 and less, must insert to page before setting text property
o.text = trows[num].cells[0].innerHTML + ' (' + num + ')';
}

function rownumchange(){
if(this.value > 0){ //activates the highlight function for the selected row (highlights it)
highlightRow.apply(trows[this.value]);
} else { //activates the highlight function for the row that is currently highlighted (turns it off)
highlightRow.apply(trows[highlightRow(true)]);
}
this.blur(); //prevent Mozilla from firing on internal events that change rownum's value
}

addEvent(rownum, 'change', rownumchange);

rownum.value = 0; //reset for browsers that remember select values on reload

while (--t > 0) {
trow = trows[t];
trow.className = 'normal';
addEvent(trow, 'click', highlightRow);
option(t);
}//end while

function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > 0) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight){
if(trow !== this) { trow.className = 'normal'; }
else if(this.className === 'normal') { rownum.value = t; }
else { rownum.value = 0; }
}
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true); //gets current index or null if none highlighted
if(typeof idx === 'number'){//there was a highlighted row
idx += way; //increment\decrement the index value
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); } //index is > 0 and a row exists at that index
else if(idx){ return highlightRow.apply(trows[1]); } //index is out of range high, go to first row
return highlightRow.apply(trows[trows.length - 1]); //index is out of range low, go to last row
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]); //none was highlighted - go to 1st if down arrow, last if up arrow
}//end function

function processkey(e){
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e);
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}//end function

addEvent(document, 'keydown', processkey);
addEvent(window, 'unload', function(){}); //optional, resets the page for browsers that remember the script state on back and forward buttons

}/* end function */)();//execute function and end script
</script>
</body>
</html>



Any questions, feel free to ask.

Note: While looking at this I realized that the two while loops could stop at 1 (--t > 0) because we don't want the 0 row (the header). So I changed both of those. They were (--t > -1).

Oh, and I came up with this alternate style section which I think is more legible:


<style type="text/css">
th, td {
font: normal 90% verdana, helvetica, ariel, sans-serif;
padding: 2px 3px;
height: 18px;
vertical-align: middle;
}
th {
font-weight: bold;
}
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: blue;
font-weight: bold;
font-size: 80%;
}
.datestatus {
width: 6.5em;
}
</style>



And, depending upon how the table is being created, the select should perhaps be moved to above the div id="results" tag.

How is the table being created?

CDias
11-10-2015, 12:18 PM
This is a great code!!! But the code applies to only one table (document.getElementById('mstrTable').rows). How should I modify the code for multiple tables on the page?

vwphillips
11-10-2015, 03:18 PM
<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
tr.highlighted2 td {
color: white;
background-color: blue;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
Current Row: <select id="rownum">
<option value="0" selected>None</option>
</select>
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>
</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>
<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
<br /><br /><br />

Current Row: <select id="rownum2">
<option value="0" selected>None</option>
</select>
<table id="mstrTable2" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>
</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>
<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">

function zxcHighlightRow(o){
var tbl=document.getElementById(o.TableID),s=document.getElementById(o.SelectID),ncls=o.NormalClass,hcls=o.HighlightClass,i=o.Highlight,k=true;
if (tbl&&tbl.rows[2]){
var rows=tbl.rows,z0=1,z1=0;
for (;z0<rows.length;z0++){
if (s&&s.getElementsByTagName('OPTION')[0]){
o=document.createElement('option');
o.value=z0;
s.appendChild(o);
o.text = rows[z0].cells[0].innerHTML+' ('+z0+')';
}
this.addevt(rows[z0],'click','change',z0);
}
s?this.addevt(s,'change','change'):null;
k?this.addevt(document,'keydown','key'):null;
this.addevt(document,'click','focus')
o=this;
o.s=s
o.tbl=tbl;
o.rows=rows;
o.hr=rows[0];
o.n=typeof(i)=='number'?i:0;
o.ncls=ncls;
o.hcls=hcls;
o.change(typeof(i)=='number'?i:0);
}
}

zxcHighlightRow.prototype={

change:function(n){
var o=this,n=typeof(n)=='number'?n:o.s?o.s.selectedIndex:0;
o.s?o.s.selectedIndex=0:null;
o.hr.className=o.ncls;
o.n=n=Math.min(Math.max(n,0),o.rows.length);
if (n>0&&o.rows[n]){
o.hr=o.rows[n]
o.hr.className=o.hcls;
o.s?o.s.selectedIndex=n:null;
}
},

focus:function(p1,e){
e.cancelBubble=true;
if (e.stopPropagation){
e.stopPropagation();
}
var eobj=e.target?e.target:e.srcElement;
while (eobj.parentNode){
if (eobj==this.tbl||eobj==this.s){
zxcHighlightRow.o=this;
return false;
}
eobj=eobj.parentNode;
}
},

key:function(p1,e){
if (zxcHighlightRow.o==this){
this.change(this.n+(e.keyCode==38?-1:e.keyCode==40?1:0));
}
},

addevt:function(o,t,f,p,p1){
var oop=this;
o.addEventListener?o.addEventListener(t,function(e){ return oop[f](p,e);},false):o.attachEvent?o.attachEvent('on'+t,function(e){ return oop[f](p,e); }):null;
}


}

new zxcHighlightRow({
TableID:'mstrTable',
SelectID:'rownum',
NormalClass:'normal',
HighlightClass:'highlighted2',
KeyDown:true
});

new zxcHighlightRow({
TableID:'mstrTable2',
SelectID:'rownum2',
NormalClass:'normal',
HighlightClass:'highlighted',
Highlight:2,
KeyDown:true
});


</script>
</body>
</html>

BIJIN P
01-08-2016, 06:22 AM
There are lots of ways. I would use version 5 events (add/attach event, rather than version 4), but without doing that, here's a way to get it to work:



<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(
function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow;

while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
trow.onclick = highlightRow;
}//end while

function highlightRow(gethighlight) {
gethighlight = gethighlight === true;
var t = trows.length, hrow;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight && trow !== this) { trow.className = 'normal'; }
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true), nextrow;
if(typeof idx === 'number'){
idx += way;
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); }
else if(idx){ return highlightRow.apply(trows[1]); }
return highlightRow.apply(trows[trows.length - 1]);
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]);
}

function processkey(e){
e = e || event;
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}

document.onkeydown = processkey;

}//end function

)();//end script
</script>
</body>
</html>



Here we go with more annotation and converting to version 5 events:


<!DOCTYPE html>
<html>
<head>
<title>Table Row Demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
tr.normal td {
color: black;
background-color: white;
}
tr.highlighted td {
color: white;
background-color: red;
}
</style>
</head>
<body>
<div id="results" class="scrollingdatagrid">
<table id="mstrTable" cellspacing="0" border="1">
<thead>
<tr>
<th>File Number</th>
<th>Date1</th>
<th>Date2</th>
<th>Status</th>
<th>Num.</th>
</tr>
</thead>
<tbody>
<tr>
<td>KABC</td>
<td>09/12/2002</td>
<td>09/12/2002</td>
<td>Submitted</td>
<td>1</td>

</tr>
<tr>
<td>KCBS</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Lockdown</td>
<td>2</td>
</tr>

<tr>
<td>WFLA</td>
<td>09/11/2002</td>
<td>09/11/2002</td>
<td>Submitted</td>
<td>3</td>
</tr>
<tr>
<td>WTSP</td>
<td>09/15/2002</td>
<td>09/15/2002</td>
<td>In-Progress</td>
<td>4</td>
</tr>
</tbody>
</table>
</div>

<script type="text/javascript">
(function() {
var trows = document.getElementById('mstrTable').rows, t = trows.length, trow, nextrow,
addEvent = (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false); //modern browsers
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, function(e){f.apply(el, [e]);}); //IE 8 and less
}:function(){return;}; //a very old browser (IE 4 or less, or Mozilla, others, before Netscape 6), so let's skip those
})();

while (--t > -1) {
trow = trows[t];
trow.className = 'normal';
addEvent(trow, 'click', highlightRow);
}//end while

function highlightRow(gethighlight) { //now dual use - either set or get the highlighted row
gethighlight = gethighlight === true;
var t = trows.length;
while (--t > -1) {
trow = trows[t];
if(gethighlight && trow.className === 'highlighted'){return t;}
else if (!gethighlight && trow !== this) { trow.className = 'normal'; }
}//end while

return gethighlight? null : this.className = this.className === 'highlighted'? 'normal' : 'highlighted';
}//end function

function movehighlight(way, e){
e.preventDefault && e.preventDefault();
e.returnValue = false;
var idx = highlightRow(true); //gets current index or null if none highlighted
if(typeof idx === 'number'){//there was a highlighted row
idx += way; //increment\decrement the index value
if(idx && (nextrow = trows[idx])){ return highlightRow.apply(nextrow); } //index is > 0 and a row exists at that index
else if(idx){ return highlightRow.apply(trows[1]); } //index is out of range high, go to first row
return highlightRow.apply(trows[trows.length - 1]); //index is out of range low, go to last row
}
return highlightRow.apply(trows[way > 0? 1 : trows.length - 1]); //none was highlighted - go to 1st if down arrow, last if up arrow
}//end function

function processkey(e){
switch(e.keyCode){
case 38: {//up arrow
return movehighlight(-1, e)
}
case 40: {//down arrow
return movehighlight(1, e);
}
default: {
return true;
}
}
}//end function

addEvent(document, 'keydown', processkey);

}/* end function */)();//execute function and end script
</script>
</body>
</html>



when i use navigation keys, i have problem with the highlighting. Since I'm Hiding a few rows on Text Search, the focus doesn't work correctly. Because focus goes to the hidden rows as well. for example ,initially if table had 10 rows, after search it has just last one row,and when i press down key, i only get highlighted row after 9 keypresses. I need the focus working straightaway on the visible rows. Please help with that

I also need your help with enter keypress. when a particular row is highlighted and i press enter i need to get the id of a column in that row and execute another function using it. please help.

jscheuer1
01-31-2016, 05:45 PM
When you say hidden, do you mean visibility hidden (with or without also positioning - say absolute perhaps?), or display none, or something else (addition of a class name perhaps - how this happens is important*)? In any case, keeping track in an array of those unseen rows would be one way of disqualifying them from inclusion and/or qualifying them for being skipped when looking ahead and back with the arrow keys. Could you give us a link to your page or show us your code? That would give us more to work on. As for Enter getting the id of the highlighted, if that's it's literal id, that should be simple enough. As any give row is highlighted, make that row's id go into a variable. Press enter, and dump that value into your "execute another function". For more details, again, show us what you have so far.

*Or consider migrating to jQuery where it's easier to tell the style of each item - say row, in a collection of elements. If that's the only criterion you have to go on, jQuery may be the way to go - though it can be worked out in ordinary javascript, just a lot more complex. The main thing is though, if there's only one way these rows become unseen, that act in itself can be used to track them. Much easier than having to tell on the fly. But, as I've been saying, to see that, we would need to see the code you're currently working from - either by you posting it, or linking to it.