...

View Full Version : shuffle table rows help



low tech
06-18-2012, 09:12 AM
Hey all

OK first, I have no idea how to begin this or if it can be done but I hope it's possible.

Sorry I don't have any js code at this point.

I'm looking for a function to shuffle a group of table rows ---- I may use more rows than I have shown here.

This is how my table appears now. I can move the table rows up and down but I would like to 'onload' and on 'reset' shuffle the rows.

If it is possible can anybody help get me started with it --- or tell me it's not doable.

<tbody id="tbody1">
<tr><td>word 5</td></tr>
<tr><td>word 3</td></tr>
<tr><td>word 2</td></tr>
<tr><td>word 4</td></tr>
<tr><td>word 1</td></tr>
</tbody>

Really appreciate any help

LT

Philip M
06-18-2012, 09:32 AM
<html>
<head>

<table>
<tbody id="tbody1">
<tr class="word5"><td id = "td1"></td></tr>
<tr class="word3"><td id = "td2"></td></tr>
<tr class="word2"><td id = "td3"></td></tr>
<tr class="word4"><td id = "td4"></td></tr>
<tr class="word1"><td id = "td5"></td></tr>
</tbody>
</table>

<script type = "text/javascript">

var words = ["word 1", "word 2", "word 3", "word 4", "word 5"];

function shuffle(Arr) {
var NewArr = Arr.slice(0);
var Range = NewArr.length;
while (Range>0) {
NewArr.push(NewArr.splice(Math.floor(Math.random()*Range),1)[0]);
Range--;
}
return NewArr;
}

var wordsShuffled =shuffle(words);

for (var i = 0; i <=4; i++) {
var cell = "td" + (i +1);
document.getElementById(cell).innerHTML = wordsShuffled[i];
}

</script>



</body>
</html>

“I don't pretend we have all the answers. But the questions are certainly worth thinking about..” - Arthur C. Clarke quotes (English Writer of science fiction, b.1917

low tech
06-18-2012, 09:56 AM
Hi Philip m

Thanks for that, really appreciated.

I'm looking at it now --- not sure if I can make it work with what I'm trying to do.

I was thinking there would be a more generic function way of doing it by using tbody1 and somehow manipulating the index of each row to move it --- but it was just a thought, I don't have a clue at this point.


The problem is I may use more than one table on a page. So id's may be difficult.

I'm using the class I have on each row to track the final position of the row ---- so basically the class goes with the word/ sentence in its row and they stay together.

At the end, after the student has moved the rows about and thinks they are in right order, I collect all the class names and join them and send to PHP --- then I know if sentences are in right order. (the class name will spell a nonsense word which I will have in DB)

Thats the only way I can think of at the moment anyway.

So I was thinking of a function that could loop through the rows and move them about up or down to mix them. Easy to say but I can't get my head around of how to do it.

Maybe I'm not thinking of this the best way.


Here is the function done by Bullant that moves the rows. Not sure if that can be manipulated or adapted in any way


function moveRow(dir){
var selRowIndex;
for(i=0; i < tbodyO.rows.length; i++){
if(tbodyO.rows[i].selected){
selRowIndex = tbodyO.rows[i].rowIndex;
i = tbodyO.rows.length;
}
}
if(selRowIndex >= 0){
switch (dir){
case 'up':
if(selRowIndex > 0){
tbodyO.insertBefore(tbodyO.removeChild(tbodyO.rows[selRowIndex]), tbodyO.rows[selRowIndex-1]);
}
break;
case 'down':
if(selRowIndex < (tbodyO.rows.length-1)){
tbodyO.insertBefore(tbodyO.removeChild(tbodyO.rows[selRowIndex+1]), tbodyO.rows[selRowIndex]);
}
}
}
}

LT

Philip M
06-18-2012, 10:02 AM
The problem is I may use more than one table on a page. So id's may be difficult


Why? If necessary repeat the script.



Here is the function done by Bullant that moves the rows. Not sure if that can be manipulated or adapted in any way


Why not ask him? He calls himself webdev1958 these days. Oh, sorry, I mean Mishu. No, that's wrong. He is iBall now.

low tech
06-18-2012, 10:35 AM
Hi philip m

Your script is cool for sure.

My script and way of tracking relies on the class staying with the row and text (which maybe a word, sentence, paragraph , image and anything I may come up with)

Using ids here for me makes it more difficult to work with. Adding ids is making more code and as is the class doesn't stay with the text though I'm sure that could be done i'm not thinking of that way.

Now, for each new test I just change the class name per row to make my key. It's fairly simple --- if I could just move the rows about it'd make it perfect.


LT

Old Pedant
06-18-2012, 09:05 PM
Philip's method will work fine for multiple instances with just a minor tweak or two.

Instead of using the IDs of the <td>s, find them positionally within the given <tbody>.



<html>
<body>
<table border="1">
<tbody id="tbody1">
<tr><td style="color: red;">WORD</td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
<tr><td></td></tr>
</tbody>
</table>
<hr/>
<table border="1">
<tbody id="tbody2">
<tr><td>(1)</td><td></td></tr>
<tr><td>(2)</td><td></td></tr>
<tr><td>(3)</td><td></td></tr>
</tbody>
</table>

<script type = "text/javascript">
var dataSet1 = ["word 1", "word 2", "word 3", "word 4", "word 5"];

var dataSet2 = ["aardvarks","armadillos","alligators"];

function shuffle(Arr,tbodyID, headRows, tdPosition)
{
if ( headRows == null ) headRows = 0;
if ( tdPosition == null ) tdPosition = 0;
var NewArr = Arr.slice(0);
var Range = NewArr.length;
while (Range>0) {
NewArr.push(NewArr.splice(Math.floor(Math.random()*Range),1)[0]);
Range--;
}
var rows = document.getElementById(tbodyID).getElementsByTagName("tr");
for ( var r = 0; r < NewArr.length; ++r )
{
var td = rows[r+headRows].getElementsByTagName("td")[tdPosition];
td.innerHTML = NewArr[r];
}
}

shuffle( dataSet1, "tbody1", 1 );
shuffle( dataSet2, "tbody2", 0, 1 );
</script>

</body>
</html>

See? Even added arguments that allow you to skip header row(s) and/or specify which <td> in the row to affect.

low tech
06-20-2012, 06:02 AM
Hi Old Pedant

Sorry for late reply

I was thinking of actually randomizing the actual table rows --- moving the rows literally and not the text within the td. (the classname should move with the rows --- I may have worked that out now actually --- not sure yet)

But I have found a perfect use for your code which I think is just a little bit more flexible and suits my needs.

Thanks to both
philip m
old pedant

low tech

low tech
06-20-2012, 03:11 PM
Hi iBall

triple A.

Awesome. I can't wait to try out that code.

Amazing. Exactly what I had in my imagination.

Absolutely fantastic:thumbsup:

LT

low tech
06-21-2012, 03:32 AM
Hi iBall

Just tried out the code and it works great but I misunderstood one thing


This also handles more than 1 tbody in a table which is common.

I thought it handled the rows in both table bodies independently.


Now, the code is one table and two table bodies --- both table body rows shuffle together

Is it possible to have the two table bodies shuffle independently of each other?

I don't mind taking a crack at it IF you say it is possible but no point in wasting time and effort if you say it is better to have two tables. So just a question really.


Another question I have is:
At the moment I give each row a class. For ex a,b,c,d,e then after the rows have been rearranged into an order I get the class names and join them and compare them via php to the string abcde if they match I know the order is correct. If not I reply try again.

Is there a better way to track the rows or is that method (the only way I could think of) an ok method? It does seem to work.

LT

Old Pedant
06-21-2012, 04:07 AM
Shoud be a trivial change to his code:


function shuffleRows(elemID){
// get the one and only <tbody> of the given <table>
var tbodyO = document.getElementById(elemID).getElementsByTagName('tbody')[0];
var tbodyRows = [], randIdxs = [];
for(i=0; i<tbodyO.rows.length; i++){
tbodyRows.push(tbodyO.rows[i]);
randIdxs.push(i);
}
randIdxs.shuffle();
var len = tbodyO.rows.length;
while(tbodyO.rows.length > 0){
tbodyO.deleteRow(0);
}
for(i=0; i<len; i++){
tbodyO.appendChild(tbodyRows[randIdxs[i]]);
}
}

Basically, I just used the single <tbody> and omitted all the indexing of his tbodyO variable.

You could also do this by passing the id of the <tbody> (instead of the <table>) in which case you just change the start of the function to


function shuffleRows(tbodyID){
// get the ref to the <tbody> from its id
var tbodyO = document.getElementById(tbodyID);
... rest same ...

Untested, but it's only logical.

low tech
06-21-2012, 04:35 AM
Hi iBall


Your original post had just 1 tbody and you didn't specify how to handle extra table data

To be honest I didn't have that idea in the beginning --- it's developed from the various input given in this thread. In practice I don't know at this stage if there will be any benefit to having one table several bodies with each body having one exercise compared to having several tables each containing one exercise. I'm still developing this and experimenting.




Old Pedant
Thanks --- i'm trying out that code now. If it works (I think it will ) then I think the next problem for me will be how to collect the classnames from each table body individually so I can check the answer. (just thinking ahead really)

For example now I do this which is working for one table.


function checkChoice(test){
//code here
var yrAns = "";
var temp;
for(i=0; i < tbodyO.rows.length; i++){
temp = tbodyO.rows[i].className;
yrAns += temp;
//alert(yrAns);
}
//var params = "answer=check&yrans=" + yrAns;
var params = "answer=check&yrans="+yrAns+"&test="+test;
console.log(params);

jQuery.ajax({

type: "POST",

url: "ef_orderedWrdCheck.php",

data: params,

rest of Ajax here

Anyway one step at a time. It may prove easier 'for me' to go the one table one test route. We'll see.

By the way my php has an array like this so I can know the name and answer to each test (example)
I may move to database later (depends)


$efanswer = array(
"test0" => "edcba",
"test1" => "whatever",
"test2" => "abcde");

//rest of php

LT

low tech
06-21-2012, 06:03 AM
Hi to anybody following this thread

So I got Old Pedant's code to work as I wished. It randomized the table bodies independently of each other. Cool. I added extra argument -- num.


function shuffleRows(elemID,num){
// get the one and only <tbody> of the given <table>
var tbodyO = document.getElementById(elemID).getElementsByTagName('tbody')[num];
//rest of code same


The test table looked like this

<table cellspacing="0" cellpadding="3" id="tb1">
<tbody>
<tr class="e"><td>the mat 5</td></tr>
<tr class="d"><td>sat on 4</td></tr>
<tr class="b"><td>fat 2</td></tr>
<tr class="c"><td>cat 3</td></tr>
<tr class="a"><td>The 1</td></tr>
</tbody>
<tbody>
<tr class="e"><td>the mat 5</td></tr>
<tr class="d"><td>sat on 4</td></tr>
<tr class="b"><td>fat 2</td></tr>
<tr class="c"><td>cat 3</td></tr>
<tr class="a"><td>The 1</td></tr>
</tbody>
</table>

BUT for me --- I think I'd better go the one table one quiz route because teh rest of teh code I have deals with moving the rows up and down and having two table bodies in one table stops that code from working which means I would have to dig into that --- so I think to keep things manageable for myself I should use on table per exercise and concentrate on the issue of how to get the results of whichever table is used into the ajax query.

I think that will be more appropriate approach for my level.

I'm very happy with what I have now.

Huge thanks to everybody.


I have one final question on what approach I should take for this.

I want to be able to reorder a sentence
ie
went market the Tom to
Tom went to the market

A sentence may of course be longer.

Should I be thinking about moving cells in a table or working with dragable divs?

Ideas are welcomed.


LT

iBall

That sounds fine. You can use classes, id's or a user customised property for each row (my preference) to check the order of the rows.

Thanks.
"id's or a user customised property for each row (my preference)" --- do you mean I can add custom html ?

low tech
06-21-2012, 11:11 AM
Hi Guys

Ok, been working on this all day hahaha
note original script by Bullant, i'm just trying to modify to suit my needs.

I've tried to go for two tables -- each table has one tbody which is one exercise.
My idea being that if I need another exercise, I push another tbodyObj into the array
and add another table.


Issue:
If you move the table rows up and down on tbody1 they work as expected.

BUT if you move the table rows up down on tbody0 they also move the rows in tbody1 :-(

I can't see or understand why --- I've tried my best and this is what I have.

Any help would as always would be fantasic. I'm probably doing it all wrong anyway haha

LT


<script type="text/javascript">
function moveRow(dir){
var selRowIndex;
for (k=0; k<tbodyObj.length; k++){
for(i=0; i < tbodyObj[k].rows.length; i++){
if(tbodyObj[k].rows[i].selected){
selRowIndex = tbodyObj[k].rows[i].rowIndex;
i = tbodyObj[k].rows.length;
}
}


if(selRowIndex >= 0){
switch (dir){
case 'up':
if(selRowIndex > 0){
tbodyObj[k].insertBefore(tbodyObj[k].removeChild(tbodyObj[k].rows[selRowIndex]), tbodyObj[k].rows[selRowIndex-1]);
}
break;
case 'down':
if(selRowIndex < (tbodyObj[k].rows.length-1)){
tbodyObj[k].insertBefore(tbodyObj[k].removeChild(tbodyObj[k].rows[selRowIndex+1]), tbodyObj[k].rows[selRowIndex]);
}
}
}
}
}//end for K loop I think it needs to be here

function selectRow(obj){
var curStatus = obj.selected;
for (k=0; k<tbodyObj.length; k++){
for(i=0; i < tbodyObj[k].rows.length; i++){
tbodyObj[k].rows[i].selected = false;
tbodyObj[k].rows[i].style.backgroundColor = 'white';
}
}
obj.selected = (curStatus == true)? false : true;
obj.style.backgroundColor = (obj.selected)? '#80FF00' : 'white';
}

function highlightRow(obj){
for (k=0; k<tbodyObj.length; k++){
for(i=0; i < tbodyObj[k].rows.length; i++){
if(tbodyObj[k].rows[i] == obj && !tbodyObj[k].rows[i].selected){
tbodyObj[k].rows[i].style.backgroundColor = '#CCCCCC';
}
}
}
}
function unHighlightRows(){
for (k=0; k<tbodyObj.length; k++){
for(i=0; i < tbodyObj[k].rows.length; i++){
if(!tbodyObj[k].rows[i].selected){
tbodyObj[k].rows[i].style.backgroundColor = 'white';
}
}
}
}

window.onload=function(){
document.getElementById('btn_down').onclick=function(){moveRow('down');}
document.getElementById('btn_up').onclick=function(){moveRow('up');}

tbodyObj = [];
tbodyObj.push(document.getElementById('tbody0'));
tbodyObj.push(document.getElementById('tbody1'));
for (k=0; k<tbodyObj.length; k++){
for(i=0; i < tbodyObj[k].rows.length; i++){
tbodyObj[k].rows[i].onclick=function(){selectRow(this);}
tbodyObj[k].rows[i].onmouseover=function(){highlightRow(this);}
tbodyObj[k].rows[i].onmouseout=unHighlightRows;
}
}
}
</script>
</head>
<body>
<table cellspacing="0" cellpadding="3">
<tbody id="tbody0">
<tr class="e"><td>the mat 5</td></tr>
<tr class="d"><td>sat on 4</td></tr>
<tr class="b"><td>fat 2</td></tr>
<tr class="c"><td>cat 3</td></tr>
<tr class="a"><td>The 1</td></tr>
</tbody>
</table>
<br />
<table cellspacing="0" cellpadding="3">
<tbody id="tbody1">
<tr class="e"><td>the mat 5</td></tr>
<tr class="d"><td>sat on 4</td></tr>
<tr class="b"><td>fat 2</td></tr>
<tr class="c"><td>cat 3</td></tr>
<tr class="a"><td>The 1</td></tr>
</tbody>
</table>
<div>
<button id="btn_down">Down</button>
<button id="btn_up" >Up</button>
</div>

low tech
06-21-2012, 12:21 PM
Hi iBall


But you now seem to be making up your requirements as you go along so it makes harder to work out what you now actually want and how you are doing it

sorry, I don't mean to give that impression.

The code that I have works perfect for a single table and is exactly what I want

which is:
a table where the rows move up and down and can be shuffled.


BUT I need the flexibility of having more than one table per page
so that is what i've been attempting to do. I did not realise the problem
of having more than one table.


If my attempt post#16 worked then i'd be done. It is testing two tables
with the flexibility to add extra table. Each table being an exercise.

But it doesn't work as I expected.

The rows in tbody1 move as expected. They do not affect tbody0.
The rows in tbody0 move as expected BUT they also move rows in tbody1.

My requirements haven't changed.

I've just decided to go with seperate tables
each table having one exercise.
That's what i've been trying to accomplish.

LT

low tech
06-21-2012, 12:40 PM
Hi iBall


Ok, then if I understand you correctly the example I posted does exactly what you want. Each table can have 1 or more tbodys. To shuffle the rows in a tbody all you need to do is pass the ID of the table to shuffleRows().

Oh I really hope not otherwise I've used a whole day for nothing:-(

This is the table from the code you posted. Great code by the way.

Anyway, that code shuffles the whole table -- both table bodies see my post #11

I tried giving ID's to each tbody and tried to get each tbody to work seperetely and that's what I thought you meant and which I wanted --- but I couldn't get that to work.
Hence, where I am now with the code #16.

I'd be very happy if you tell me i'm wrong tho.


//id on table shuffles both tbodies
<table id="tbl1">
<tbody>
<tr><td>word 5</td></tr>
<tr><td>word 4</td></tr>
<tr><td>word 3</td></tr>
<tr><td>word 2</td></tr>
<tr><td>word 1</td></tr>
</tbody>
<tbody>
<tr><td>word 44</td></tr>
<tr><td>word 33</td></tr>
<tr><td>word 22</td></tr>
<tr><td>word 11</td></tr>
</tbody>
</table>

I'm trying to do

<table>
<tbody id="id0">
<tr><td>word 5</td></tr>
<tr><td>word 4</td></tr>
<tr><td>word 3</td></tr>
<tr><td>word 2</td></tr>
<tr><td>word 1</td></tr>
</tbody>
<tbody id="id1">
<tr><td>word 44</td></tr>
<tr><td>word 33</td></tr>
<tr><td>word 22</td></tr>
<tr><td>word 11</td></tr>
</tbody>
</table>

or (each table one exercise --- I think this might be easier when I try to get the result of each exercise by ajax)

<table>
<tbody id="id0">
<tr><td>word 5</td></tr>
<tr><td>word 4</td></tr>
<tr><td>word 3</td></tr>
<tr><td>word 2</td></tr>
<tr><td>word 1</td></tr>
</tbody>
</table>


<table>
<tbody id="id1">
<tr><td>word 44</td></tr>
<tr><td>word 33</td></tr>
<tr><td>word 22</td></tr>
<tr><td>word 11</td></tr>
</tbody>
</table>

Does it make sense.

Did I misunderstand your code?

LT

low tech
06-21-2012, 01:08 PM
Hi iBall


This is your original requirement.

I'm looking for a function to shuffle a group of table rows ---- I may use more rows than I have shown here.

Yes, you are right sorry.

The shuffle works fine -- perfect.

Like I said I have the single table with shuffle -- all works fine. I thought I could just add more tables or tbodies but not so simple.

I see this is where my wires are crossed.

I'm trying to make the shuffle function work with the rest of code. The shuffle works fine but when I have two table bodies the move up down doesn't work fine. post#16 (to see it)

Basically post 16 is where the trouble is --- which I can't work out. If I solve that I think it will work fine when I add the shuffle back in.

LT

low tech
06-21-2012, 02:52 PM
Hi iBall



iBall:::: Ok, then if I understand you correctly the example I posted does exactly what you want. Each table can have 1 or more tbodys.

Yep, again spot on --- I have worked out where I was going wrong --- I can now have two tables both will shuffle --- no problem.


Can't believe I got so mixed up it the coding.


So my only issue is with code at post#16 ------ maybe I should put that in a new thread --- since it's a separate issue?

Sorry for the mix up. My brain is fried hahaha


LT

low tech
06-21-2012, 03:52 PM
Hi


iBall::: maybe start afresh in a new thread with your issue in post 16.

Yep good idea --- better to stay focused.

LT

thanks



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum