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 TorontoSoftware DeveloperAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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 TorontoSoftware DeveloperAuthor Commented:
Could you please explain your Li. 16-17?
0
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
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

APD TorontoSoftware DeveloperAuthor 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 TorontoSoftware DeveloperAuthor 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
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
APD TorontoSoftware DeveloperAuthor Commented:
Thank you, I will post another question shortly, hopefully it will be easier.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
JavaScript

From novice to tech pro — start learning today.