JavaScript to sort Listbox

Hi Experts,

I'm trying to write a JavaScript function that sort items in a listbox by text. The function start at line 82 and ends at 116.

However, this does not work, and when I add a breakpoint at line 98 and 100, I see that arrTextsSorted does indeed sort, but if I break at 103 and 106, I see that the listbox items are not being chnaged. As well, I have not tested the idea association yet between 106 and 111, so if you spot an error, please let me know.

<!DOCTYPE html>

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <style>
            #left{
                float: left;
                margin-left: 50px;
            }  

            .assoc_buttons{
                margin-left: 20px;
                width: 8em;
                margin-right: 20px;
                vertical-align: middle;
            }
            #right{
                clear: both;
                vertical-align: middle;   
            }
        </style>

    </head>
    <body>
      
    <form id="frm" name="frm">
        
        <select name="left" id="left" size="7">
            <option value="5">Location C</option>
            <option value="8">Location E</option>
        </select>
        
        <input type="button" class="assoc_buttons" name="btn_add" value="< Add" onclick="moveItem('right', 'left');"><br>
        <input type="button" class="assoc_buttons" name="btn_add_all" value="<< Add All" onclick="add_all();"><br>
        <input type="button" class="assoc_buttons" name="btn_del" value="Delete >" onclick="del();"><br>
        <input type="button" class="assoc_buttons" name="btn_del_all" value="Delete All >>" onclick="del_all();">

        <select name="right" id="right" size="7">
            <option value="4">Location A</option>
            <option value="6">Location B</option>
            <option value="2">Location D</option>
            <option value="10">Location F</option>
            <option value="1">Location G</option>
            <option value="9">Location H</option>
            <option value="7">Location I</option>
            <option value="3">Location J</option>
            
        </select>
        
    </form>
    
<script type="text/javascript">

    function moveItem(lstFrom, lstTo){
        
        var from = document.getElementById(lstFrom);
        var to = document.getElementById(lstTo);
        
        if (from.selectedIndex == -1){
            alert ("No Locations were selected to be added.");
            return false;
        }
        
        var i = from.selectedIndex;
        var newVal = from.options[i].value;
        var newText = from.options[i].text;
        
        //Remove from item
        from.removeChild(from.options[i]);
        
        //Add to item
        to.options[to.options.length] = new Option(newText, newVal);
        
        //sort from
        reSort(lstTo);        
    }
    
    function reSort(listName){
        
        var lstBox = document.getElementById(listName);
         
        var arrTexts = new Array();
        var arrValues = new Array();
        
        //Copy options to arrays
        for (i = 0; i < lstBox.length; i++){
            arrTexts[i] = lstBox.options[i].text;
            arrValues[i] = lstBox.options[i].value;
        }
        
        //Sort texts and copy to new array
        var arrTextsSorted = new Array();
        arrTextsSorted = arrTexts;
        arrTextsSorted = arrTextsSorted.sort();
        
        for (i = 0; i < lstBox.length; i++){
            
            //list texts in alpha-order
            lstBox.options[i].Text = arrTextsSorted[i];
            
            //Locate text's assoc ID
            for (j = 0; j < arrTexts.length; j++){
                
                if (arrTextsSorted[i].match(arrTexts[j])){
                    lstBox.options[i].value = arrValues[j];
                    break;
                }
            }
        }
            
    }


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

Open in new window


Thank you in advance
APD TorontoAsked:
Who is Participating?
 
Robert SchuttSoftware EngineerCommented:
What is not working and in which browser? That last code you posted works fine for me.

I meant for lines 120-122 to be combined into 1 line but it works either way.
var arrTextsSorted = arrTexts.slice().sort();

Open in new window


.match (line 133) is meant for testing against a regular expression, but in this situation it does work (because no special characters happen to exist in the text values).

I added a debug field to show the values have also been set in the correct order.
capture output
0
 
Robert SchuttSoftware EngineerCommented:
As long as you have your debugger open, have a look at arrTexts after the sort, you will see the original is also sorted because the assignment on line 97 doesn't make a copy. You could use:
var arrTextsSorted = arrTexts.slice().sort();

Open in new window


Then, just a small error on line 103: "text" should be all lowercase.

In this case speed is probably not an issue but looking through the array to match the value is pretty slow. Here is an alternative using an indexing array:
    function reSort(listName){
        
        var lstBox = document.getElementById(listName);
         
        var arrTexts = new Array();
        var arrValues = new Array();
        var arrIndex = new Array();
        
        //Copy options to arrays
        for (i = 0; i < lstBox.length; i++){
            arrTexts[i] = lstBox.options[i].text;
            arrValues[i] = lstBox.options[i].value;
            arrIndex[i] = i;
        }

        arrIndex.sort(function(a, b){
            return lstBox.options[a].text < lstBox.options[b].text ? -1 : (lstBox.options[a].text > lstBox.options[b].text ? 1 : 0);
        });

        for (i = 0; i < lstBox.length; i++){
            
            //list texts in alpha-order
            lstBox.options[i].text = arrTexts[arrIndex[i]];
            lstBox.options[i].value = arrValues[arrIndex[i]];
        }
    }

Open in new window

0
 
APD TorontoAuthor Commented:
Could you please explain your Li. 16-17?
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Robert SchuttSoftware EngineerCommented:
Sure, that's the whole trick of that method. Glad to see you're interested in more than the quick fix!

The javascript sort() function can be called with a custom compare function. This function compares "a" to "b" and returns whether they are the same, a is smaller or b is smaller. The sort() function then knows whether they should be swapped or not (or something a bit smarter).

In this case I compare the text fields from the related options so if a=1 and b=2 then actually the texts of options 1 and 2 are compared but the indexes get swapped (because the sort function is called on the arrIndex variable, have a look at that in the debugger right after the sort). This can save time and memory (haven't tested it out for this exact situation but have used it before in other situations and it can be real significant).

Then after the sort you don't have to look for the right value to go with a text anymore as you can just put both the text and the value back in the options, in the position found in arrIndex.
0
 
APD TorontoAuthor Commented:
But what I don't understand is where do you get a and b.

For my code, I fixed Li 97, but I am not sure what you mean about 103. Also, when I monitor my loop I see lstBox.options[0]'s label changes to "location a", but the text still remain "location c". I added the following, but it doe not help.

            lstBox.options[i].Text = arrTextsSorted[i];
            lstBox.options[i].text = arrTextsSorted[i];
            lstBox.options[i].Label = arrTextsSorted[i];

Open in new window

0
 
Robert SchuttSoftware EngineerCommented:
The argument to the sort() function is basically a callback function. The arguments a and b are supplied by the sort() function, which calls that function a number of times with different arguments to determine the new order of the array. You can see exactly what's happening by logging a and b to the console in the callback function. Something like (untested):
console.log('a='+a+',b='+b);

Open in new window


Your original line 103 is:
lstBox.options[i].Text

Open in new window

which should give an error because javascript is case-sensitive, no such property as Text (or Label) exists, it should just be:
lstBox.options[i].text

Open in new window

0
 
APD TorontoAuthor Commented:
Still not working, this is my latest code:

<!DOCTYPE html>

<html>
    <head>
        <title>TODO supply a title</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <style>
            #assoc-container{
                /*border: 1px solid black;*/
                margin: 15px auto;
                width: 300px;
                height: 112px;
            }
            
            #left{
               float: left;
               display: inline;
               width: 90px;
                
            }  

            .assoc_buttons{
                width: 100px;
                margin-bottom: 7px;
            }
            
            #assoc_btn_container{
               float: left;
               display: inline;
               width: 100px;  
               margin-left: 10px;
               margin-right: 10px;
            } 
            
            #right{
               float: left;
               display: inline;
               width: 90px;
                
            }
        </style>

    </head>
    <body>
      
    <form id="frm" name="frm">

        <div id="assoc-container">
            
            <select name="left" id="left" size="7">
                <option value="5">Location C</option>
                <option value="8">Location E</option>
            </select>

            <div id="assoc_btn_container">
                <input type="button" class="assoc_buttons" name="btn_add" value="< Add" onclick="moveItem('right', 'left');"><br>
                <input type="button" class="assoc_buttons" name="btn_add_all" value="<< Add All" onclick="add_all();"><br>
                <input type="button" class="assoc_buttons" name="btn_del" value="Delete >" onclick="del();"><br>
                <input type="button" class="assoc_buttons" name="btn_del_all" value="Delete All >>" onclick="del_all();">
            </div>
            
            <select name="right" id="right" size="7">
                <option value="4">Location A</option>
                <option value="6">Location B</option>
                <option value="2">Location D</option>
                <option value="10">Location F</option>
                <option value="1">Location G</option>
                <option value="9">Location H</option>
                <option value="7">Location I</option>
                <option value="3">Location J</option>

            </select>
            
        </div>

    </form>
    
<script type="text/javascript">

    function moveItem(lstFrom, lstTo){
        
        var from = document.getElementById(lstFrom);
        var to = document.getElementById(lstTo);
        
        if (from.selectedIndex == -1){
            alert ("No Locations were selected to be added.");
            return false;
        }
        
        var i = from.selectedIndex;
        var newVal = from.options[i].value;
        var newText = from.options[i].text;
        
        //Remove from item
        from.removeChild(from.options[i]);
        
        //Add to item
        to.options[to.options.length] = new Option(newText, newVal);
        
        //sort from
        reSort(lstTo);        
    }
    
    function reSort(listName){
        
        var lstBox = document.getElementById(listName);
         
        var arrTexts = new Array();
        var arrValues = new Array();
        
        //Copy options to arrays
        for (i = 0; i < lstBox.length; i++){
            arrTexts[i] = lstBox.options[i].text;
            arrValues[i] = lstBox.options[i].value;
        }
        
        //Sort texts and copy to new array
        var arrTextsSorted = new Array();
        arrTextsSorted = arrTexts;
        arrTextsSorted = arrTextsSorted.slice().sort();
        
        for (i = 0; i < lstBox.length; i++){
            
            //list texts in alpha-order
//            lstBox.options[i].Text = arrTextsSorted[i];
            lstBox.options[i].text = arrTextsSorted[i];
  //          lstBox.options[i].Label = arrTextsSorted[i];
            //Locate text's assoc ID
            for (j = 0; j < arrTexts.length; j++){
                
                if (arrTextsSorted[i].match(arrTexts[j])){
                    lstBox.options[i].value = arrValues[j];
                    break;
                }
            }
        }
            
    }


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

Open in new window

0
 
APD TorontoAuthor Commented:
Thank you, I will post another question shortly, hopefully it will be easier.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.