By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,626 Members | 2,202 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,626 IT Pros & Developers. It's quick & easy.

Ordering rows in a table

P: n/a
Hi

I have a javascript problem that has been annoying me for two days now
and thought that a javascript expert might have the magic solution.

I am populating a table dynamically from the database and I am trying
to allow the user to order the rows in the table using up and down
arrows.

The function I am using is:

function moveContactRow(direction)
{
var tempVal; //stores temporary value while swapping hidden values
rowIndex =
parseInt(window.event.srcElement.parentElement.par entElement.index);
if((rowIndex == 0 && direction > 0) || (rowIndex ==
id_listTable.rows.length - 1 && direction < 0) || (rowIndex > 0 &&
rowIndex < id_listTable.rows.length - 1))
{
if(id_listTable.rows[rowIndex].cells[0].swapNode)
{
id_listTable.rows[rowIndex +
direction].cells[0].swapNode(id_listTable.rows[rowIndex].cells[0]);
id_listTable.rows[rowIndex +
direction].cells[1].swapNode(id_listTable.rows[rowIndex].cells[1]);
id_listTable.rows[rowIndex +
direction].cells[2].swapNode(id_listTable.rows[rowIndex].cells[2]);
tempVal = document.all('hidID' + rowIndex).value;
document.all('hidID' + rowIndex).value = document.all('hidID' +
[rowIndex + direction]).value;
document.all('hidID' + [rowIndex + direction]).value = tempVal;
document.all('hid' + rowIndex).value = rowIndex + direction;
document.all('hid' + [rowIndex + direction]).value = rowIndex;
}
}
}
To call the function the arrows have the following code:

upArrow - onclick="moveContactRow(-1)
DownArrow - onclick="moveContactRow(1)

The good thing is that the table rows move correctly, but the values
written to the hidden fields (prefixed with hid or hidID) aren't always
correct.

Any ideas on whats happening?

Any help is greatly appreciated.

Thanks

Brendan

Sep 6 '05 #1
Share this Question
Share on Google+
6 Replies


P: n/a
Br*************@Singularity.co.uk wrote:
Hi

I have a javascript problem that has been annoying me for two days now
and thought that a javascript expert might have the magic solution.

I am populating a table dynamically from the database and I am trying
to allow the user to order the rows in the table using up and down
arrows.

The function I am using is:

function moveContactRow(direction)
{
var tempVal; //stores temporary value while swapping hidden values
rowIndex =
parseInt(window.event.srcElement.parentElement.par entElement.index);
if((rowIndex == 0 && direction > 0) || (rowIndex ==
id_listTable.rows.length - 1 && direction < 0) || (rowIndex > 0 &&
rowIndex < id_listTable.rows.length - 1))
{
if(id_listTable.rows[rowIndex].cells[0].swapNode)
{
id_listTable.rows[rowIndex +
direction].cells[0].swapNode(id_listTable.rows[rowIndex].cells[0]);
id_listTable.rows[rowIndex +
direction].cells[1].swapNode(id_listTable.rows[rowIndex].cells[1]);
id_listTable.rows[rowIndex +
direction].cells[2].swapNode(id_listTable.rows[rowIndex].cells[2]);
tempVal = document.all('hidID' + rowIndex).value;
document.all('hidID' + rowIndex).value = document.all('hidID' +
[rowIndex + direction]).value;
document.all('hidID' + [rowIndex + direction]).value = tempVal;
document.all('hid' + rowIndex).value = rowIndex + direction;
document.all('hid' + [rowIndex + direction]).value = rowIndex;
}
}
}
To call the function the arrows have the following code:

upArrow - onclick="moveContactRow(-1)
DownArrow - onclick="moveContactRow(1)

The good thing is that the table rows move correctly, but the values
written to the hidden fields (prefixed with hid or hidID) aren't always
correct.

Any ideas on whats happening?

Any help is greatly appreciated.

Thanks

Brendan

Hi Brendan,

I wouldn't have used swapNodes to handle the re-ordering, instead I
would have an array that represents the table and then used the "sort"
function of array to re index the array and then redraw the table from
the array.
Consider this javascript:

------------------------ JAVASCRIPT ---------------------------
// An Array of data.
var aTable = {
{"1", "First Name", "First Address", "First Phone" },
{"2", "Second Name", "Second Address", "Second Phone" },
{"3", "Third Name", "Third Address", "Third Phone" }};

// A var to define which column is ordered
var nCurrentColumn = 0;

// A function the wrap the sorting and rendering;
function OrderCol( nCol ){
// @nCol defines what index the Array is to be index on.
nCurrentColumn = nCol;
aTable.sort(sortTable);
RenderTable();
}
// The Function to the array.
function sortTable (a,b){
if (a[nCurrentColumn]<b[nCurrentColumn]) return -1
if (a[nCurrentColumn]>b[nCurrentColumn]) return 1
return 0;
}

// A function to step through the array to render a table
function RenderTable(){
eTableBody = document.getElementById("tableBody");
eTableBody.innerHTML="";
for( var i=0;i<aTable.length;i++ ){
var eRow = document.createElement( "tr" );
for( var j=0; j<aTable[i].length;j++ ){
var eCell = document.createElement( "td" );
eCell.appendChild( document.createTextNode( aTable[i][j] ) );
eRow.appendChild(eCell);
}
eTableBody.appendChild( eRow );
}
}

// Using the onload event to start the table rendering
window.onload = function(){ OrderCol(0); }

---------------------------------------------------------
And this HTML :
------------------------ HTML ---------------------------

<table>
<thead>
<tr>
<td onclick="OrderCol(0);">KEY</td>
<td onclick="OrderCol(1);">Name</td>
<td onclick="OrderCol(2);">Address</td>
<td onclick="OrderCol(3);">Phone</td>
</tr>
</thead>
<tbody id="tableBody"></tbody>
</table>

---------------------------------------------------------

You will probably want to handle the control of direction so if a column
has been clicked twice for indexing you invert the direction of the
ordering. All you need to do to achive this is to have an indicator set
either to 1 or -1 and then in the sortTable function return the value
multiplied by this indicator.

For Example
if (a[nCurrentColumn]<b[nCurrentColumn]) return ( -1 * nDirection );
if (a[nCurrentColumn]>b[nCurrentColumn]) return ( 1 * nDirection );
return 0;

Hope this helps

Andy

----------------------------------------------------------------------
http://km0ti0n.blunted.co.uk/blog
http://km0ti0n.blunted.co.uk/mozXPath
http://km0ti0n.blunted.co.uk
----------------------------------------------------------------------

Sep 6 '05 #2

P: n/a

"Andrew Scott" <An****@compan.net> wrote in message
news:11*************@corp.supernews.com...
Br*************@Singularity.co.uk wrote:

Hi Brendan,

I wouldn't have used swapNodes to handle the re-ordering, instead I would
have an array that represents the table and then used the "sort" function
of array to re index the array and then redraw the table from the array.


I agree - getting into the DOM for this is nasty work. ;^)

Instead load your data into an abstracted element (like an array) and
rewrite the table each time - it's very fast on the client and sooo much
simpler.

Andrews code will work just fine (and a lot of people may prefer it) but if
you're interested I've got an abstraction component that might help. It
maintains an ordered set of objects (essentially abstracting Andrews array
into an object and providing management and sorting methods). Sorry, long
URL coming:

<
http://www.depressedpress.com/depres...ered/Index.cfm >

There's an example on that page of sorting a table using the component.

Using this Andrews original code might look like this:

// This creates a new ordered collection and makes the "ID" field the
key
MyData = new DP_ObCollectionOrdered("id", Object);
// Add the data - you need to name the properties if you want to sort
them here (Andrew's is less verbose in that respect).
MyData.add( {id: "1", name:"First Name", address:"First Address",
phone:"First Phone" } );
MyData.add( {id: "2", name:"Second Name", address:"Second Address",
phone:"Second Phone" } );
MyData.add( {id: "3", name:"Third Name", address:"Third Address",
phone:"Third Phone" } );

You could then sort the data by any property like this:

MyData.sortByProp('id', 'Numeric', 'asc');

MyData.sortByProp('address', 'AlphaNoCase', 'asc');

MyData.sortByProp('name', 'Alpha', 'desc');

And so forth.

You also get all sorts of "rank" (position in the collection) methods - you
can swap elements, move them up or down one or more steps or just move them
around using only a method call.

Also, before you pull your hair out: IE won't let you write into a tbody
tag... it's a damn pain in that respect. It doesn't even give a good error
(just an "unknown exception" or some such). Andrew's code will work
perfectly fine in FireFox but will error in IE on the
eTableBody.innerHTML=""; (well... at least it does for me).

Because of this it's usually simpler to just write the whole table (with the
header) into a <div> (the example on my site does this and works in both IE
and FireFox). It's not elegant, but it works.

Jim Davis
Sep 6 '05 #3

P: n/a
Br*************@Singularity.co.uk wrote:
Hi

I have a javascript problem that has been annoying me for two days now
and thought that a javascript expert might have the magic solution.

I am populating a table dynamically from the database and I am trying
to allow the user to order the rows in the table using up and down
arrows.


If all you are doing is moving rows up or down based on whether the up
or down arrow is clicked, I think you can do this much more easily.

Your use of document.all will prevent your code from working in a good
number of browsers. Use of window.event will restrict usage almost
entirely to IE.

Solutions for the document.all issue are on the group FAQ:

<URL:http://jibbering.com/faq/#FAQ4_15>

Solutions for window.event are here:

<URL:http://www.quirksmode.org/js/introevents.html>

Here is a simple script for moving rows up or down. The buttons could be
added using an onload function to reduce code bloat and users without
JavaScript would not see the buttons at all.

<script type="text/javascript">

function moveR( el, x )
{
while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
el = el.parentNode;
}
var t = el.parentNode;
var i = el.rowIndex + x;

if ( i < 0 ) i += t.rows.length;
if ( i == t.rows.length ) i = 0;

t.removeChild(el);
var nRow = t.insertRow( i );
t.replaceChild(el, nRow);
}

</script>

<table>
<tr>
<td>
<input type="button" value="Move up" onclick="moveR(this, -1);">
<input type="button" value="Move down" onclick="moveR(this, 1);">
</td>
<td>row 0</td>
</tr>
<tr>
<td>
<input type="button" value="Move up" onclick="moveR(this, -1);">
<input type="button" value="Move down" onclick="moveR(this, 1);">
</td>
<td>row 1</td>
</tr>
<tr>
<td>
<input type="button" value="Move up" onclick="moveR(this, -1);">
<input type="button" value="Move down" onclick="moveR(this, 1);">
</td>
<td>row 2</td>
</tr>
</table>

[...]

--
Rob
Sep 7 '05 #4

P: n/a
RobG wrote:
[...]
Here is a simple script for moving rows up or down. The buttons could be
added using an onload function to reduce code bloat and users without
JavaScript would not see the buttons at all.


Had a bit more of a play, the following is more concise but maybe more
difficult to maintain as a result:

function moveR( el, x )
{
while ( el.parentNode && 'tr' != el.nodeName.toLowerCase() ){
el = el.parentNode;
}
var t = el.parentNode;
var i = (el.rowIndex + +x)% t.rows.length;
t.replaceChild(t.removeChild(el), t.insertRow(i));
}

The extra '+' in '(el.rowIndex + +x)' ensures that x is a number even if
passed as a string.
[...]

--
Rob
Sep 7 '05 #5

P: n/a
Jim Davis wrote:
"Andrew Scott" <An****@compan.net> wrote in message
news:11*************@corp.supernews.com...
Br*************@Singularity.co.uk wrote:

Hi Brendan,

I wouldn't have used swapNodes to handle the re-ordering, instead I would
have an array that represents the table and then used the "sort" function
of array to re index the array and then redraw the table from the array.

I agree - getting into the DOM for this is nasty work. ;^)

Instead load your data into an abstracted element (like an array) and
rewrite the table each time - it's very fast on the client and sooo much
simpler.

Andrews code will work just fine (and a lot of people may prefer it) but if
you're interested I've got an abstraction component that might help. It
maintains an ordered set of objects (essentially abstracting Andrews array
into an object and providing management and sorting methods). Sorry, long
URL coming:

<
http://www.depressedpress.com/depres...ered/Index.cfm >

There's an example on that page of sorting a table using the component.

Using this Andrews original code might look like this:

// This creates a new ordered collection and makes the "ID" field the
key
MyData = new DP_ObCollectionOrdered("id", Object);
// Add the data - you need to name the properties if you want to sort
them here (Andrew's is less verbose in that respect).
MyData.add( {id: "1", name:"First Name", address:"First Address",
phone:"First Phone" } );
MyData.add( {id: "2", name:"Second Name", address:"Second Address",
phone:"Second Phone" } );
MyData.add( {id: "3", name:"Third Name", address:"Third Address",
phone:"Third Phone" } );

You could then sort the data by any property like this:

MyData.sortByProp('id', 'Numeric', 'asc');

MyData.sortByProp('address', 'AlphaNoCase', 'asc');

MyData.sortByProp('name', 'Alpha', 'desc');

And so forth.

You also get all sorts of "rank" (position in the collection) methods - you
can swap elements, move them up or down one or more steps or just move them
around using only a method call.

Also, before you pull your hair out: IE won't let you write into a tbody
tag... it's a damn pain in that respect. It doesn't even give a good error
(just an "unknown exception" or some such). Andrew's code will work
perfectly fine in FireFox but will error in IE on the
eTableBody.innerHTML=""; (well... at least it does for me).

Because of this it's usually simpler to just write the whole table (with the
header) into a <div> (the example on my site does this and works in both IE
and FireFox). It's not elegant, but it works.

Jim Davis

I'd have to agree that rewriting the whole table is better. And the use
of literal object over arrays is deffinatly more benifical. I'd
normally populate a table like this from an xml file, which would also
define the column data too. But with the xml data source I'd still have
to generate an array as the the XMLDOM doesn't have a sort method. Jim,
your ObCollectionOrdered script has some nice features.

I have to Admit I've never actually tried writing to innerHTML of a
tbody element. I try to avoid innerHTML as much as possible (just out
of habit). I probably would have done this :

while( eTableBody.firstChild ) { eTableBody.removeNode(
eTableBody.firstChild ); }

or

eTableBody = eTableBody.replaceNode( eTableBody.cloneNode( false ) );

Though there are many many ways to archive this. using innerHTML is
very fast. But from a users point rewriting the whole table or just a
section of the table doesn't matter it just preference of what you would
prefer to do.


Sep 7 '05 #6

P: n/a
Andrew Scott wrote:
[...]
I have to Admit I've never actually tried writing to innerHTML of a
tbody element.
Don't, it will fail in IE. Microsoft say don't use innerHTML on tables.

tbody element. I try to avoid innerHTML as much as possible (just out
of habit). I probably would have done this :

while( eTableBody.firstChild ) { eTableBody.removeNode(
eTableBody.firstChild ); }

or

eTableBody = eTableBody.replaceNode( eTableBody.cloneNode( false ) );


That's cool, the above iterative method will slow as the number of rows
increases, but this method should not.

[...]
--
Rob
Sep 7 '05 #7

This discussion thread is closed

Replies have been disabled for this discussion.