Link to home
Start Free TrialLog in
Avatar of maunded
maunded

asked on

SOrt list of items from text box

Hi,
I have some PHP code which outputs a list of items from a database.
I want to be able to have a text box which will sort those items based on user input  eg, if a user presses 'e' all the items that start with e will be listed, if they press ed all the items that start with ed will....etc etc.
Ive seen this done, I just cant figure out how to do it.  I could do it with PHP but it means reloading the page etc and I want to avoid that if possible.
Thanks in advance
Dean.
Avatar of third
third
Flag of Philippines image

Avatar of maunded
maunded

ASKER

Nope, thats not even close to what Im after.
I want a text box then a list of items in a table underneath
Typing in the text box sorts the items as I have described above.
I originally had this as a drop down box, but now the list of item is getting too big, and it needs to be sorted.
I hope I have explained this properly, if I havent plese let me know.
Hi maunded,

you can not get data from the database without reloading the page ... one very inefficient way would be to get ALL the data on the page ... and play with the data through javascript and sort in any order that you want ... but that's not as good as reloading the page with new data from database ...
Avatar of maunded

ASKER

Ayesha, thanks for your comment.  I have to get all the data anyway, Im just trying to make it easy to search through that list of data.  I could requery the database based on the user input, but since I have to get all the data anyway (the user might want to scroll through all the options) then its better to use javascript to sort or filter them, I just dont know how to do this
Is something like this more like what you're looking for?  You just have to populate the select with the options you need.  It's a small example, but I tried to pick words that would have letters in common so it shows how it selects the words.  Hope that helps.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<script type="text/javascript">
function init()
{
  theSel = document.getElementById("theOptions");
  opts = new Array();
  for (var i = 0; i < theSel.options.length; i ++)
    opts[i] = theSel.options[i].text;
  opts.sort();

  key = document.getElementById("keyword");
  key.onkeyup = function () {matchOptions(key.value);};
}

function matchOptions(val)
{
  for (var i = theSel.options.length - 1; i >= 0; i --)
    theSel.options[i] = null;
  for (var i = 0; i < opts.length; i ++)
  {
    if (opts[i].indexOf(val) == 0)
      theSel.options[theSel.options.length] = new Option(opts[i], opts[i], false, false);
  }
}

window.onload = init;
</script>
</head>

<body>
<input type="text" id="keyword" /><br />
<select id="theOptions" size="10">
  <option value="a">a</option>
  <option value="anvil">anvil</option>
  <option value="apple">apple</option>
  <option value="animal">animal</option>
  <option value="abracadabra">abracadabra</option>
  <option value="b">b</option>
  <option value="bee">bee</option>
  <option value="become">become</option>
  <option value="bat">bat</option>
  <option value="batman">batman</option>
  <option value="barb">barb</option>
  <option value="cow">cow</option>
  <option value="c">c</option>
</select>
</body>
</html>
Avatar of maunded

ASKER

I can see that is getting very close to what I am after, Im increasing the point value on this one since I think what I am trying to do is harder than I first thought.
Instead of a combo box, can this be changed to a list of items in a table?  Here is my PHP code (Ive place "theOptions" where I thought it might work, but it didnt :(

<table  class = \"no-border-table\" width = \"80%\" id=\"terminal_table\">");
print ("<tr><td align=\"center\"><b>Active Terminals</b></td></tr>");
print ("<tr><td align=\"right\">");
$terminal_list_query = "SELECT DISTINCT TerminalID, TerminalCommonName FROM CustomerTerminals_View WHERE CustomerUserName = '$login_id' ORDER BY TerminalCommonName ASC;";
$terminal_list_array_result = mssql_query($terminal_list_query);

FOR ($count=0; $count < mssql_num_rows($terminal_list_array_result); ++$count)
      {      $terminal_list_result = mssql_fetch_array($terminal_list_array_result);
      if ($color=="#e6e6e6") $color="#f6f6f6";
                        else $color="#e6e6e6";
            if ($terminal_id == $terminal_list_result[0]) {
                print ("<tr id = \"theOptions\" bgcolor=\"$color\"><td align=\"left\"><font color=\"#ff0000\">$terminal_list_result[1]</font></td></tr>");
            }
            else {
             print ("<tr id = \"theOptions\" bgcolor=\"$color\"><td align=\"left\"><a href=\"$document_name?tid=$terminal_list_result[0]&poll_id=$poll_id\">$terminal_list_result[1]</a></td></tr>");
            };
      };
print ("</td></td></table id=\"terminal_table\">
Give the script below a shot.  The only thing you have to do is to make sure that the table has an id of "theOptions".  It looks like you only have one cell per row, but just in case, the script is set to sort/search the table for whatever is in the first column of the table.  So if you decide to switch up your table, you have to change the script accordingly (I commented where you should change).  Hope this helps.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<script type="text/javascript">
function init()
{
  // first we need to sort the table
  theSel = document.getElementById("theOptions");
  sortTable(theSel, 0);  // change the "0" to whatever column you want to sort/search by.  1 = 2nd col, 2 = 3rd col, etc.

  // now we implement the search stuff
  opts = new Array();
  for (var i = 0; i < theSel.rows.length; i ++)
    opts[i] = theSel.rows[i].cells[0].innerHTML;
  opts.sort();

  key = document.getElementById("keyword");
  key.onkeyup = function () {matchOptions(key.value);};
}

function matchOptions(val)
{
  for (var i = theSel.rows.length - 1; i >= 0; i --)
    theSel.rows[i].style.display = "none";
  for (var i = 0; i < opts.length; i ++)
  {
    if (opts[i].indexOf(val) == 0)
      theSel.rows[i].style.display = "";
  }
}

function sortTable(obj, col)
{
  var tbl = obj;
  while (tbl.tagName.toLowerCase() != "table")
    tbl = tbl.parentNode;
  var tbody = tbl.getElementsByTagName("tbody")[0];

  var arr = new Array();
  for (var i = 1; i < tbl.rows.length; i ++)
    arr[arr.length] = tbl.rows[i].cells[col].innerHTML;
 
  arr.sort(mySort);

  var str = "";
  for (var j = 0; j < arr.length; j ++)
    str += "\n" + arr[j];

  for (var i = 0; i < arr.length; i ++)
  {
    if (arr[i] == tbl.rows[i+1].cells[col].innerHTML)
      continue;
    else
    {
      var ctr = i + 1;
      while (tbl.rows[ctr].cells[col].innerHTML != arr[i])
        ctr ++;
      var rowToSwitch = tbl.rows[ctr];
      var temp = tbl.rows[i+1];
      tbody.replaceChild(rowToSwitch, temp);
      tbody.appendChild(temp);
    }
  }
}

function mySort(a, b)
{
  var aTest = a;
  var bTest = b;
  var testDateA = new Date(a); // used to test for date types
  if (!isNaN(a) && !isNaN(b))
  {
    aTest = parseInt(a);
    bTest = parseInt(b);
  }
  else if (testDateA != "NaN" && testDateA != "Invalid Date")
  {
    aTest = testDateA.getTime();
    bTest = new Date(b).getTime();
  }

  if (aTest > bTest)
    return 1;
  if (aTest < bTest)
    return -1;
  else
    return 0;
}

window.onload = init;
</script>
</head>

<body>
<input type="text" id="keyword" /><br />
<table id="theOptions">
  <tr><td>a</td></tr>
  <tr><td>anvil</td></tr>
  <tr><td>apple</td></tr>
  <tr><td>animal</td></tr>
  <tr><td>abracadabra</td></tr>
  <tr><td>b</td></tr>
  <tr><td>bee</td></tr>
  <tr><td>become</td></tr>
  <tr><td>bat</td></tr>
  <tr><td>batman</td></tr>
  <tr><td>barb</td></tr>
  <tr><td>cow</td></tr>
  <tr><td>c</td></tr>
</table>
</body>
</html>
Avatar of maunded

ASKER

Sorry, that didnt work.  I dont know much about javascript, but this line dosent seem right...
  var tbody = tbl.getElementsByTagName("tbody")[0];
There is no tag name tbody
Am I missing something?
Avatar of maunded

ASKER

OK, hangon, ive kind of got it working, i put the onload function in the <body> tag,
but now when i type something in the text box, everything disappears,
but we are definitely getting somewhere!!!
Avatar of maunded

ASKER

...also, the table used to be sorted by name (from the sql script), now it seems random each time
Okay, one question at a time:
- in browsers like Mozilla, the rows in a table are automatically added to the tbody if there isn't one defined.  That's why you need to look for the tbody, since it will be there even if you didn't explicitly include that tag.
- there WAS something being done onload already.  The fact that you're seeing "random" order of the rows proves it - the elements are sorted (more on this in a sec) in the init() function, which is called onload.  window.onload = init is equivalent to <body onLoad="init()">, but it leaves your html and javascript separate, which makes things easier to maintain.
- the "randomness" is because I didn't see the <font> and <a> tags in your PHP.  The script was sorting using the entire string between <td> and </td>.  So, it saw things like "<font color='#ff0000'>Value</font>" and "<a href=something>Value</a>" and sorted based those strings.  I fixed it to avoid that problem, you can use the script below.

If you still have problems, let me know.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<script type="text/javascript">
function init()
{
  // first we need to sort the table
  theSel = document.getElementById("theOptions");
  sortTable(theSel, 0);  // change the "0" to whatever column you want to sort/search by.  1 = 2nd col, 2 = 3rd col, etc.

  // now we implement the search stuff
  opts = new Array();
  for (var i = 0; i < theSel.rows.length; i ++)
    opts[i] = theSel.rows[i].cells[0].childNodes[0].innerHTML;
  opts.sort();

  key = document.getElementById("keyword");
  key.onkeyup = function () {matchOptions(key.value);};
}

function matchOptions(val)
{
  for (var i = theSel.rows.length - 1; i >= 0; i --)
    theSel.rows[i].style.display = "none";
  for (var i = 0; i < opts.length; i ++)
  {
    if (opts[i].indexOf(val) == 0)
      theSel.rows[i].style.display = "";
  }
}

function sortTable(obj, col)
{
  var tbl = obj;
  while (tbl.tagName.toLowerCase() != "table")
    tbl = tbl.parentNode;
  var tbody = tbl.getElementsByTagName("tbody")[0];

  var arr = new Array();
  for (var i = 1; i < tbl.rows.length; i ++)
  {
    var theTd = tbl.rows[i].cells[col];
    arr[arr.length] = theTd.childNodes[0].innerHTML;
  }
  arr.sort(mySort);

  var str = "";
  for (var j = 0; j < arr.length; j ++)
    str += "\n" + arr[j];

  for (var i = 0; i < arr.length; i ++)
  {
    if (arr[i] == tbl.rows[i+1].cells[col].childNodes[0].innerHTML)
      continue;
    else
    {
      var ctr = i + 1;
      while (tbl.rows[ctr].cells[col].childNodes[0].innerHTML != arr[i])
        ctr ++;
      var rowToSwitch = tbl.rows[ctr];
      var temp = tbl.rows[i+1];
      tbody.replaceChild(rowToSwitch, temp);
      tbody.appendChild(temp);
    }
  }
}

function mySort(a, b)
{
  var aTest = a;
  var bTest = b;
  var testDateA = new Date(a); // used to test for date types
  if (!isNaN(a) && !isNaN(b))
  {
    aTest = parseInt(a);
    bTest = parseInt(b);
  }
  else if (testDateA != "NaN" && testDateA != "Invalid Date")
  {
    aTest = testDateA.getTime();
    bTest = new Date(b).getTime();
  }

  if (aTest > bTest)
    return 1;
  if (aTest < bTest)
    return -1;
  else
    return 0;
}

window.onload = init;
</script>
</head>

<body>
<input type="text" id="keyword" /><br />
<table id="theOptions">
  <tr><td><font color="#ff0000">a</font></td></tr>
  <tr><td><font color="#ff000f">anvil</font></td></tr>
  <tr><td><font color="#ff00f0">apple</font></td></tr>
  <tr><td><font color="#ff00ff">animal</font></td></tr>
  <tr><td><font color="#ff0000">abracadabra</font></td></tr>
  <tr><td><font color="#ff000f">b</font></td></tr>
  <tr><td><a href="#">bee</a></td></tr>
  <tr><td><font color="#ff00ff">become</font></td></tr>
  <tr><td><a href="#">bat</a></td></tr>
  <tr><td><font color="#ff000f">batman</font></td></tr>
  <tr><td><font color="#ff00f0">barb</font></td></tr>
  <tr><td><font color="#ff00ff">cow</font></td></tr>
  <tr><td><font color="#ff0000">c</font></td></tr>
</table>
</body>
</html>
Avatar of maunded

ASKER

Thanks for your help so far dakyd,
I now get an error:
childNodes[0].innerHTML is null or not an object,
The sort function dosent seem to be working, I changed my sql to sort desc and it printed it desc.
I do have another javascript function which uses div and span tags to hide a table, would this cause a problem?
Hm ... that's odd, I'm pretty sure I replicated what your PHP should output in the example I posted.  Can you post the other javascript function you're using, and the html source that your PHP outputs?  I don't need the full source, just the table and its rows.  Better yet, if it's available online somewhere, could you post a link?

At this point, my guess is that there is some white space between <td> and whatever the next tag is (whether that be <a> or <font>) that's causing a problem.  Some browsers generate text nodes for white space, and text nodes don't have innerHTML's, which would explain your error.  But your PHP string seems to output it consecutively, and like I said, I need to see the html source to be sure.  Anyhow, let me know.
Avatar of maunded

ASKER

Sure...heres the html output from the php code:
<div id="Layer1">
<!-- Get Number of Terminals and form a list box to change the active terminal -->
<input type="text" id="keyword">
<table  class = "no-border-table" width = "80%" id = "theOptions" >
<tr>
<td align="center"><b>Active Terminals</b></td></tr><tr>
<td align="right"><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59400781&poll_id=Poll C">Aero - IL-76-1</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59415324&poll_id=Poll C">Aero - SMC 500</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59404532&poll_id=Poll C">AMS Roof</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59416560&poll_id=Poll C">B - Glasse Island WA</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59405068&poll_id=Poll C">B - Gneering Shl QLD</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59414332&poll_id=Poll C">B - Kingston Reef WA</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59414333&poll_id=Poll C">L - Point Lookout QLD</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59404658&poll_id=Poll C">S - SAR Buoy 1</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59414334&poll_id=Poll C">Vec - SkyNet</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59409687&poll_id=Poll C">Vec 501</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59414326&poll_id=Poll C">Vec 505</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59400827&poll_id=Poll C">Vec 87</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><a href="scada_page.php?tid=59409688&poll_id=Poll C">Vec 90</a>
             </td>
             </tr><tr bgcolor="#f6f6f6"><td align="left"><a href="scada_page.php?tid=59400619&poll_id=Poll C">Z - Fishing NZ1</a>
             </td>
             </tr><tr bgcolor="#e6e6e6"><td align="left"><font color="#ff0000">Z-Aero - IL-76-2</font>
            </td>
            </tr></td></td></table id = "theOptions" >
</table id="user_data"></div>

The other javascript function is here:

if (document.getElementById){
document.write('<style type="text/css">\n')
document.write('.submenu{display: none;}\n')
document.write('</style>\n')
}
function SwitchMenu(obj){
      if(document.getElementById){
      var el = document.getElementById(obj);
      var ar = document.getElementById("masterdiv").getElementsByTagName("span");
            if(el.style.display != "block"){
                  for (var i=0; i<ar.length; i++){
                        if (ar[i].className=="submenu")
                        ar[i].style.display = "none";
                  }
                  el.style.display = "block";
            }else{
                  el.style.display = "none";
            }
      }
}

Thanks again
D.
Hm, this line looks weird:

<tr>
  <td align="right">
    <tr bgcolor="#e6e6e6">
      <td align="left">
        <a href="scada_page.php?tid=59400781&poll_id=Poll C">Aero - IL-76-1</a>
      </td>
    </tr>

I added the spacing for emphasis, but you've got a <tr> immediately following a <td>.  That looks a bit strange, though judging from the way you closed your table, it may have been intentional?  This also looks weird though:
</td></td></table id = "theOptions" >

Even if you leave the <td><tr> combination alone at the top, you should have </tr></td> instead of </td></td>.  You also shouldn't have an id on the closing tag.  I think the strange table structure may be confusing the script.  Start with that, then we'll go from there.  Hope that helps.
Oops, my last post should've said:
>> Even if you leave the <td><tr> combination alone at the top, you should have </td></tr></table> instead of </td></td></table>.

I'm getting tired ... I'll have to get back to you tomorrow.  G'luck with this in the mean time.
Avatar of maunded

ASKER

You were right!!
My masses of nested tables were confusing me, I had way too many <td> and <tr>
The search script works fine, only one thing, is there a way to make it case insensitive?
Thanks dakyd, you have healed me immensly
Oh, the id in the closing tag is for my reference......Im going to have to do something about all these nested tables.
Case insensitive is just a minor tweak - give this a shot.  I changed the example to reflect the different cases, it'll both sort them properly and search for the right one regardless of case.  If you do want to put something that denotes the </table> as closing the "theOptions" table, I'd suggest HTML comments:
</table> <!-- closes "theOptions" -->
It keeps your markup clean and valid, but still lets you know exactly what the </table> tag is for.  Anyhow, hope that helps.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
<script type="text/javascript">
function init()
{
  // first we need to sort the table
  theSel = document.getElementById("theOptions");
  sortTable(theSel, 0);

  opts = new Array();
  for (var i = 0; i < theSel.rows.length; i ++)
    opts[i] = theSel.rows[i].cells[0].childNodes[0].innerHTML.toLowerCase();
  opts.sort();

  key = document.getElementById("keyword");
  key.onkeyup = function () {matchOptions(key.value);};
}

function matchOptions(val)
{
  var lowerVal = val.toLowerCase();
  for (var i = theSel.rows.length - 1; i >= 0; i --)
    theSel.rows[i].style.display = "none";
  for (var i = 0; i < opts.length; i ++)
  {
    if (opts[i].toLowerCase().indexOf(val) == 0)
      theSel.rows[i].style.display = "";
  }
}

function sortTable(obj, col)
{
  var tbl = obj;
  while (tbl.tagName.toLowerCase() != "table")
    tbl = tbl.parentNode;
  var tbody = tbl.getElementsByTagName("tbody")[0];

  var arr = new Array();
  for (var i = 1; i < tbl.rows.length; i ++)
  {
    var theTd = tbl.rows[i].cells[col];
    arr[arr.length] = theTd.childNodes[0].innerHTML.toLowerCase();
  }  
  arr.sort(mySort);

  var str = "";
  for (var j = 0; j < arr.length; j ++)
    str += "\n" + arr[j];

  for (var i = 0; i < arr.length; i ++)
  {
    if (arr[i] == tbl.rows[i+1].cells[col].childNodes[0].innerHTML.toLowerCase())
      continue;
    else
    {
      var ctr = i + 1;
      while (tbl.rows[ctr].cells[col].childNodes[0].innerHTML.toLowerCase() != arr[i])
        ctr ++;
      var rowToSwitch = tbl.rows[ctr];
      var temp = tbl.rows[i+1];
      tbody.replaceChild(rowToSwitch, temp);
      tbody.appendChild(temp);
    }
  }
}

function mySort(a, b)
{
  var aTest;
  var bTest;
  var testDateA = new Date(a); // used to test for date types
  if (!isNaN(a) && !isNaN(b))
  {
    aTest = parseInt(a);
    bTest = parseInt(b);
  }
  else if (testDateA != "NaN" && testDateA != "Invalid Date")
  {
    aTest = testDateA.getTime();
    bTest = new Date(b).getTime();
  }
  else
  {
    aTest = a.toLowerCase();
    bTest = b.toLowerCase();
  }

  if (aTest > bTest)
    return 1;
  if (aTest < bTest)
    return -1;
  else
    return 0;
}

window.onload = init;
</script>
</head>

<body>
<input type="text" id="keyword" /><br />
<table id="theOptions">
  <tr><td><a href="#">a</a></td></tr>
  <tr><td><font color="#ff0000">anvil</font></td></tr>
  <tr><td><a href="#">apple</a></td></tr>
  <tr><td><font color="#ff000f">animal</font></td></tr>
  <tr><td><a href="#">abracadabra</a></td></tr>
  <tr><td><font color="#ff00f0">b</font></td></tr>
  <tr><td><a href="#">bee</a></td></tr>
  <tr><td><font color="#ff00ff">become</font></td></tr>
  <tr><td><a href="#">bat</a></td></tr>
  <tr><td><font color="#ff0f00">batman</font></td></tr>
  <tr><td><a href="#">barb</a></td></tr>
  <tr><td><font color="#ff0f0f">cow</font></td></tr>
  <tr><td><a href="#">c</a></td></tr>
  <tr><td><font color="#ff0ff0">cOwBoY</font></td></tr>
  <tr><td><a href="#">Anvil</a></td></tr>
  <tr><td><font color="#ff0fff">Bust</font></td></tr>
</table>
</body>
</html>
Avatar of maunded

ASKER

Thanks dakyd, thats cool, but now it is reversly case sensitive, I mean, if I type an 'a' all the A... come up, but if I type 'A, i get nothing
Thanks again for your help on this
ASKER CERTIFIED SOLUTION
Avatar of dakyd
dakyd

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of maunded

ASKER

Excellent!!
Thanks for you help...Grade A Expert!!
Sure thing, glad you got what you wanted.  Thanks for the points.