Sorting <SELECT> elements: .sort is not a function

Discussion in 'Javascript' started by Teo, Aug 21, 2007.

  1. Teo

    Teo Guest

    Dear all,

    I would like to sort the elements of a <SELECT> element.

    I tried with

    document.forms.filter_form.server_filter.options.sort(
    function(a,b) {
    // cache values
    var v1 = a.text.toLowerCase();
    var v2 = b.text.toLowerCase();
    // compare
    if (v1 > v2) return(1);
    if (v1 < v2) return(-1);
    return(0);
    }
    );

    but I get the following message:

    Error: document.forms.filter_form.server_filter.options.sort is not a
    function

    document.forms.filter_form.server_filter.options is an array: I can
    access and change
    document.forms.filter_form.server_filter.options.length and access the
    elements (e.g., document.forms.filter_form.server_filter.options.
    Why cannot I also access the sort method?

    Many thanks for any hint.

    Matteo
    Teo, Aug 21, 2007
    #1
    1. Advertising

  2. Teo

    RobG Guest

    On Aug 21, 8:46 pm, Teo <> wrote:
    > Dear all,
    >
    > I would like to sort the elements of a <SELECT> element.
    >
    > I tried with
    >
    > document.forms.filter_form.server_filter.options.sort(
    > function(a,b) {
    > // cache values
    > var v1 = a.text.toLowerCase();
    > var v2 = b.text.toLowerCase();
    > // compare
    > if (v1 > v2) return(1);
    > if (v1 < v2) return(-1);
    > return(0);
    > }
    > );
    >
    > but I get the following message:
    >
    > Error: document.forms.filter_form.server_filter.options.sort is not a
    > function
    >
    > document.forms.filter_form.server_filter.options is an array:


    Trust the error message, options is not a javascript Array, it is a
    DOM HTML collection, which implements the NodeList interface:

    <URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection
    >



    I can
    > access and change
    > document.forms.filter_form.server_filter.options.length and access the
    > elements (e.g., document.forms.filter_form.server_filter.options.


    Yes, per the spec.

    > Why cannot I also access the sort method?


    Because the NodeList interface doesn't implement it, a HTML collection
    isn't a javascript Array. Your function should include loading the
    options into an array first, then sort them and finally re-position
    them in the collection.


    --
    Rob
    RobG, Aug 21, 2007
    #2
    1. Advertising

  3. Teo

    Guest

    On Aug 21, 2:23 pm, RobG <> wrote:
    > On Aug 21, 8:46 pm, Teo <> wrote:
    >
    >
    >
    > > Dear all,

    >
    > > I would like to sort the elements of a <SELECT> element.

    >
    > > I tried with

    >
    > > document.forms.filter_form.server_filter.options.sort(
    > > function(a,b) {
    > > // cache values
    > > var v1 = a.text.toLowerCase();
    > > var v2 = b.text.toLowerCase();
    > > // compare
    > > if (v1 > v2) return(1);
    > > if (v1 < v2) return(-1);
    > > return(0);
    > > }
    > > );

    >
    > > but I get the following message:

    >
    > > Error: document.forms.filter_form.server_filter.options.sort is not a
    > > function

    >
    > > document.forms.filter_form.server_filter.options is an array:

    >
    > Trust the error message, options is not a javascript Array, it is a
    > DOM HTML collection, which implements the NodeList interface:
    >
    > <URL:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection
    >
    >
    >
    > I can
    >
    > > access and change
    > > document.forms.filter_form.server_filter.options.length and access the
    > > elements (e.g., document.forms.filter_form.server_filter.options.

    >
    > Yes, per the spec.
    >
    > > Why cannot I also access the sort method?

    >
    > Because the NodeList interface doesn't implement it, a HTML collection
    > isn't a javascript Array. Your function should include loading the
    > options into an array first, then sort them and finally re-position
    > them in the collection.
    >

    But the length is writable. It's slightly different than a nodeList,
    which should raise an exception on setting length. This feature/bug is
    included for backwards compatibility to NS3, I believe. It's actually
    quite useful for adding/removing options.

    You might be able to get away with using sort() in a generic context
    (sort is an Array generic). Most likely, IE will not run this code,
    ignoring the spec rec.

    Array.prototype.sort.call( options, sortMethod );

    I haven't actually tried in IE.

    Post your results up.

    This will work in IE:

    var o = { "1":1, "2":2, "3":3, "0":0, length:3 };
    Array.prototype.sort.call( o );

    Garrett

    > --
    > Rob
    , Aug 22, 2007
    #3
  4. Hi Matteo,

    Teo wrote: -
    >
    > I would like to sort the elements of a <SELECT> element.
    >


    Later RobG wrote: -
    > > Why cannot I also access the sort method?

    >
    > Because the NodeList interface doesn't implement it, a HTML collection
    > isn't a javascript Array. Your function should include loading the
    > options into an array first, then sort them and finally re-position
    > them in the collection.


    I never new that; but it makes me feel better. I had previously (see below)
    had to unload an options collection into an array to sort it, purely (or so
    I thought at the time) to get around the problem of my having a "header" row
    at option[0]. The fact that the exercise had to be undertaken regardless is
    strangely comforting.

    Anyway, FWIW there is an example of just such select-list-sorting below. If
    you look at the jobList SELECT list you'll see that the onclick event calls
    the showDetails() function. If the selectedIndex is zero (they clicked on
    the "header" row) then I first check that there's more than one row to sort
    and then I pop-up a <div> to ask them what key (select list column) to sort
    on. (Could this be done with x/y pixel co-ords for the click?) I then unload
    the options[] collection (except for element [0]) into a JavaScript array
    and sort it before loading it back into the select-list. (FYI If they
    clicked on a row other than the "header" I drill-down into a details
    screen/frame)

    Hope it helps 'cos (at least to me) it sounds relevant to what you're trying
    to do. (Sorry to reproduce the whole thing so soon after posting it to
    another question but cut/pasting would take some time and then I'd probably
    miss out a bit, or it wouldn't make sense out of context. Either way it's
    diskspace not trees so just don't print it all :)

    Cheers Richard Maher

    PS. The code also contains RobG's suggestion (or my dodgy implementation of
    it :) of using node-cloning to speed up performance when tearing down a
    select-list before repopulating it. Thanks again Rob.

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

    <html>

    <meta name="author" content="Richard Maher"/>
    <meta name="description" content="VMS Queue lookup example"/>
    <meta http-equiv="Page-Enter"
    content="revealtrans(duration=1.5,transition=13)"/>

    <head>

    <style>

    body
    {
    color: Black;
    background-color: White;
    font-family: Times;
    font-size: 16px;
    font-weight: normal;
    font-style: normal;
    margin-left: 5px;
    margin-right: 5px;
    text-align: left;
    }

    select#jobList option
    {
    white-space: pre;
    }

    select#queList option
    {
    white-space: pre;
    }

    .header
    {
    color: Turquoise;
    font-size: 22px;
    font-weight: bold;
    }

    .credits
    {
    color: Turquoise;
    font-family: Georgia;
    }

    .waiting
    {
    width: 100%;
    text-align: right;
    font-family: Georgia;
    font-size: 150%;
    font-weight: bold;
    }

    .greenScreen
    {
    color: Lime;
    background-color: Black;
    font-family: Fixed-Width, Monospace;
    white-space: pre;
    }

    .revLeft
    {
    background-color: AliceBlue;
    color: Black;
    font-family: Fixed-Width, Monospace;
    font-weight: normal;
    font-size: 14px;
    text-align: left;
    }

    .revRight
    {
    background-color: AliceBlue;
    color: Black;
    font-family: Fixed-Width, Monospace;
    font-weight: normal;
    font-size: 14px;
    text-align: right;
    }

    .floater
    {
    position: absolute;
    z-index: 1000;
    visibility: hidden;
    left: 83px;
    top: 123px;
    padding: 0px;
    font-family: Fixed-Width, Monospace;
    font-weight: normal;
    font-size: 14px;
    }

    .sortPanel
    {
    background-color: AliceBlue;
    color: blue;
    border: thin ridge blue;
    position: absolute;
    z-index: 1000;
    visibility: hidden;
    left: 455px;
    top: 242px;
    width: 115px;
    height: 170px;
    margin: 5px;
    padding: 0px;
    }

    .sortHead
    {
    text-align: center;
    color: Black;
    font-size: 16px;
    font-weight: bold;
    }

    .options
    {
    font-family: Fixed-Width, Monospace;
    font-weight: normal;
    font-size: 14px;
    background-color: AliceBlue;
    color: Black;
    white-space: pre;
    }

    </style>

    <script type="text/javascript" src="common.js"></script>

    <script type="text/javascript">

    function msgField(name, offset, length)
    {
    this.name = name;
    this.offset = offset;
    this.length = length;
    }

    var field = new Array(5);
    field[0] = new msgField("entryNumber", 0, 10);
    field[1] = new msgField("jobName" , 11, 39);
    field[2] = new msgField("jobStatus" , 51, 15);
    field[3] = new msgField("queName" , 67, 31);
    field[4] = new msgField("queType" , 99, 10);
    field[5] = new msgField("queStatus" , 110, 10);

    var msgGetInfo = "10";
    var jobInfo = "11";
    var msgQueName = "40";
    var jobByQue = "60";
    var queName = "41";
    var eofInfo = "99";
    var eofLen = 3;
    var jobMsgLen = 115;
    var queNameLen = 31;
    var msgQue = "";
    var lastMsgQue = "";
    var spaceFill = " ";
    var zeroFill = "0000000000";
    var maxRows = "00000"; //Unlimited
    var maxReadTime = 10000;
    var waitInterval = 700;
    var sortKey = 0;
    var sortIndex = 0;
    var optIndex = 0;
    var strA = "";
    var strB = "";
    var alertMsg = "Error retrieving job entry information:\n";
    var timeoutMsg = "Request timeout has expired.<br />" +
    "Increase the timeout value if server is under load."

    var rc;
    var outPad;
    var ok;
    var msgEntry;
    var intId;
    var abortBackColor;
    var sendBackColor;
    var abortValue;
    var cancelCount;
    var closureType;
    var target;
    var waitCount;
    var waitColors;
    var waitText;
    var bytesIn;
    var queList;
    var quePopUp;
    var eventTarget;
    var radioTarget;
    var labelTarget;
    var labels;
    var labelIndex;
    var sortBy;
    var exitSort;
    var selectClone;
    var swapClone;
    var evt;
    var keyCode;

    function load()
    {
    selectRef = document.getJobs.jobList;
    selectClone = selectRef.cloneNode(true);
    queList = document.queOptions.queList;
    waitColors = new Array("blue","lime","yellow","orange","red");
    waitText = document.getElementById("stallMsg");
    quePopUp = document.getElementById("queInfo");
    labels = document.getElementsByTagName("label");
    sortBy = document.getElementById("sortBy");
    exitSort = document.getElementById("r7");

    try
    {
    chan = parent.cornucopiae.chan;
    chan.setTimeout(maxReadTime);
    document.getJobs.queName.focus();
    }
    catch(err)
    {
    return false;
    }
    }

    function lockDown()
    {

    document.getJobs.send.disabled=true;
    sendBackColor = document.getJobs.send.style.backgroundColor;
    document.getJobs.send.style.backgroundColor="Silver";
    document.getJobs.send.blur();

    document.getJobs.queName.disabled=true;
    document.getJobs.entryNumber.disabled=true;
    document.getJobs.jobList.disabled=true;

    abortValue=document.getJobs.reqAbort.value;
    abortBackColor = document.getJobs.reqAbort.style.backgroundColor;
    document.getJobs.reqAbort.style.backgroundColor="Red";
    document.getJobs.reqAbort.disabled=false;

    cancelCount = zeros;

    return true;
    }

    function openUp()
    {
    document.getJobs.reqAbort.disabled=true;
    document.getJobs.reqAbort.style.backgroundColor=abortBackColor;
    document.getJobs.reqAbort.value=abortValue;

    document.getJobs.send.style.backgroundColor=sendBackColor;
    document.getJobs.send.disabled=false;
    document.getJobs.queName.disabled=false;
    document.getJobs.entryNumber.disabled=false;
    if (selectRef.options.length > 1)
    document.getJobs.jobList.disabled=false;

    document.getJobs.queName.focus();

    return true;
    }

    function sendOOB(OOBchar)
    {
    if (document.getJobs.reqAbort.disabled)
    {
    alert("Request already complete.");
    return;
    }

    cancelCount++
    chan.sendUrgentData(OOBchar);
    document.getJobs.reqAbort.value="Aborts Sent " + String(cancelCount);
    document.getJobs.reqAbort.blur();

    return;
    }

    function enter(nextfield,e)
    {
    evt = e || window.event;

    try
    {
    target = evt.srcElement.name;
    }
    catch (err)
    {
    target = evt.target.name;
    }

    if (evt.type == "keypress")
    {
    keyCode = evt.which || evt.keyCode;

    if ((keyCode == 8) ||
    (keyCode == 9) ||
    (keyCode == 45) ||
    (keyCode == 46) ||
    (keyCode == 37) ||
    (keyCode == 39))
    return true;
    else
    if (keyCode == 13)
    {
    nextfield.focus();
    return false;
    }
    else
    {
    if ((target == "entryNumber") &&
    (keyCode < 48 || keyCode > 57))
    return false;
    else
    return true;
    }
    }
    }

    function selectQue()
    {
    if ((queList.selectedIndex >= queList.length) ||
    (queList.selectedIndex == -1))
    {
    document.getJobs.queName.focus();
    return true;
    }

    document.getJobs.queName.value =
    queList.options[queList.selectedIndex].text.rTrim();
    document.getJobs.send.focus();

    return true;
    }

    function queLookup()
    {
    msgQue = document.getJobs.queName.value.toUpperCase();
    if (msgQue == lastMsgQue)
    return true;

    lastMsgQue = msgQue;
    quePopUp.style.visibility="hidden";

    if (msgQue.rTrim() == "")
    return true;

    queList.size = 2;
    queList.length = zeros;

    outPad = spaceFill.substring(0, (spaceFill.length - msgQue.length));
    chan.sendMessage(msgQueName.concat(msgQue,outPad));

    recType = recvAndGet(recTypeLen);
    if (!recType)
    return;

    while (recType == queName)
    {
    if (chan.readMessage(queNameLen) == queNameLen)
    msgQue = chan.getString(0,queNameLen);
    else
    return true;

    queList.options[queList.length] = new Option (msgQue, msgQue);

    recType = recvAndGet(recTypeLen);
    }

    if (recType == errorInfo)
    {
    if (chan.readMessage() < errLenLen)
    reportError("Error receiving Error Length from server");

    return true;
    }

    if (recType != eofInfo)
    {
    reportError("Invalid recType " + recType + " received from
    server");
    return true;
    }

    if (queList.length == zeros)
    return true;

    if (queList.length == 1 && lastMsgQue.rTrim() == msgQue.rTrim())
    return true;

    if (queList.length > 2)
    if (queList.length < 7)
    queList.size=queList.length;
    else
    queList.size=7;

    queList.selectedIndex = -1;
    quePopUp.style.visibility="visible";

    return true;
    }

    function jobLookup()
    {
    msgQue = document.getJobs.queName.value.toUpperCase();
    msgEntry = document.getJobs.entryNumber.value;
    if (msgEntry.length > zeros && parseInt(msgEntry,10) == zeros)
    msgEntry = "";

    if (msgEntry.length != zeros && msgQue.rTrim() != "")
    {
    alert("Please enter a Queue Name or a Job Entry Number, but not
    both.");
    return true;
    }

    lockDown();

    document.getJobs.recCount.value = 0;

    outPad = "";
    ok = true;
    msgEntry = "";

    selectRef.size = 1;
    swapClone = selectClone.cloneNode(true);
    selectRef.parentNode.replaceChild(swapClone, selectRef);
    selectRef = document.getJobs.jobList;

    if (msgQue.rTrim() == "")
    {
    msgEntry = document.getJobs.entryNumber.value;
    outPad = zeroFill.substring(0, (zeroFill.length -
    msgEntry.length));
    chan.sendMessage(msgGetInfo.concat(outPad,msgEntry,maxRows));
    }
    else
    {
    outPad = spaceFill.substring(0, (spaceFill.length -
    msgQue.length));
    chan.sendMessage(jobByQue.concat(msgQue,outPad));
    }

    waitCount = 0
    chan.setTimeout(waitInterval);
    dclAST("getResponse()");

    return true;
    }

    function getResponse()
    {
    bytesIn = chan.readMessage(recTypeLen);
    if (bytesIn == 0)
    {
    if (waitCount == waitColors.length)
    {
    reportError(timeoutMsg);
    return;
    }
    else
    {
    if (waitText.innerHTML == "")
    {
    waitText.style.color = waitColors[waitCount];
    waitText.innerHTML = "Waiting. . .";
    waitCount++
    }
    else
    {
    waitText.innerHTML = "";
    }
    dclAST("getResponse()");
    return;
    }
    }

    if (bytesIn != recTypeLen)
    {
    reportError("Error receiving reply from server 1");
    return;
    }

    waitText.innerHTML = "";
    chan.setTimeout(maxReadTime);

    recType = chan.getString(0,recTypeLen);

    if (recType == jobInfo)
    {
    rc = 1;
    dclAST("processJobs()");
    }
    else
    {
    if (recType == errorInfo)
    {
    dclAST("processError()");
    }
    else
    {
    reportError("Unknown message type " + recType);
    return;
    }
    }

    return;
    }

    function processError()
    {
    if (chan.readMessage() < errLenLen)
    {
    reportError("Error receiving Error Length from server");
    return;
    }

    errMsgLen = parseInt(chan.getString(0,errLenLen),10);
    alert(alertMsg + chan.getString(errLenLen,errMsgLen));
    openUp();

    return;
    }

    function processJobs()
    {
    if (chan.readMessage(jobMsgLen) != jobMsgLen)
    {
    alert ("Error receiving Job Information from server");
    return;
    }

    if (cancelCount == zeros)
    {
    document.getJobs.recCount.value = rc;

    jobMsg = chan.getString(0,10) + "|" +
    chan.getString(10,39) + "|" +
    chan.getString(49,15) + "|" +
    chan.getString(64,31) + "|" +
    chan.getString(95,10) + "|" +
    chan.getString(105,10);

    selectRef.options[selectRef.options.length] = new Option (jobMsg,
    jobMsg);

    rc++;
    if (rc < 6)
    selectRef.size = rc;
    }

    if (chan.readMessage(recTypeLen) != recTypeLen)
    {
    reportError("Error receiving reply from server 2");
    return;
    }

    recType = chan.getString(0,recTypeLen);
    if (recType == jobInfo)
    {
    dclAST("processJobs()");
    return;
    }

    if (selectRef.length != 1)
    selectRef.selectedIndex = -1;

    openUp();

    if (recType != eofInfo)
    {
    reportError("Error receiving reply from server 3");
    return;
    }

    if (chan.readMessage(eofLen) != eofLen)
    {
    reportError("Error receiving reply from server 4");
    return;
    }

    closureType = chan.getString(0,eofLen);

    if (closureType == "CAN" || cancelCount != zeros)
    alert("Request curtailed\nby operator.");
    else
    if (closureType != "EOF")
    reportError("Error receiving reply from server 5");

    return;
    }

    function showDetails()
    {
    if (selectRef.selectedIndex == zeros)
    {
    selectRef.options[zeros].selected=false;
    selectRef.selectedIndex = -1;
    if(selectRef.length < 3)
    alert("Nothing to Sort.")
    else
    {
    sortBy.style.visibility="visible";
    exitSort.checked=true;
    exitSort.focus();
    }
    return false;
    }

    parent.entry_details.getReady();
    parent.document.getElementById("main").rows="30px,0px,*";
    return true;
    }

    function menuMove(e)
    {
    evt = e || window.event;

    eventTarget = eventTarget=evt.srcElement || evt.currentTarget;

    if (eventTarget.type == "radio")
    {
    radioTarget = eventTarget;
    for (labelIndex = 0; labelIndex < labels.length; labelIndex++)
    if (labels[labelIndex].htmlFor == radioTarget.id)
    {
    labelTarget=labels[labelIndex];
    break;
    }
    }
    else
    {
    labelTarget = eventTarget;
    radioTarget = document.getElementById(labelTarget.htmlFor)
    }

    if (evt.type == "mouseover")
    {
    labelTarget.style.color = "turquoise";
    radioTarget.checked = true;
    }

    if (evt.type == "mouseout")
    labelTarget.style.color = "blue";

    return true;
    }

    function sortIt(keyField)
    {
    var sortScratch = new Array();
    sortScratch.length = selectRef.length - 1;

    for (sortIndex=0; sortIndex<sortScratch.length; sortIndex++)
    sortScratch[sortIndex] = selectRef.options[sortIndex + 1].value;

    sortKey = keyField;
    sortScratch.sort(colCompare);

    optIndex = 1;
    for (sortIndex in sortScratch)
    {
    selectRef.options[optIndex].value = sortScratch[sortIndex];
    selectRef.options[optIndex].text = sortScratch[sortIndex];
    optIndex++;
    }

    return;

    }

    function colCompare(a,b)
    {
    strA =
    a.substr(field[sortKey].offset,field[sortKey].length).toUpperCase();
    strB =
    b.substr(field[sortKey].offset,field[sortKey].length).toUpperCase();

    if (strA < strB)
    return -1;

    if (strA > strB)
    return 1;

    return zeros;

    }

    function hideQues()
    {
    if (quePopUp.style.visibility != "hidden")
    quePopUp.style.visibility="hidden";

    return;

    }

    </script>

    </head>

    <body onload="load()">

    <br /><span class="header">Example Client for Tier3 DEMO Application
    Server on VMS<br /></span>
    <br /><hr><br />

    <form name="getJobs">
    <div style="font-size: 14px">

    Queue Name:
    <input
    type="text"
    class="revLeft"
    style="text-transform: uppercase"
    onkeypress="return enter(document.getJobs.entryNumber, event)"
    onkeyup="return queLookup()"
    name="queName"
    maxlength=31
    size=31
    title="Enter the Queue Name [Wildcards '*' and '%' are
    permitted]"
    />

    Job Entry Number:
    <input
    type="text"
    class="revRight"
    onfocus="hideQues();"
    onkeypress="return enter(document.getJobs.send, event)"
    name="entryNumber"
    maxlength=10
    size=10
    dir="rtl"
    title="Enter the Job Entry Number [Default is All My Jobs]"
    />

    <input
    type="button"
    style="background-color:Turquoise; color:Black;"
    onfocus="hideQues();"
    onclick="jobLookup()"
    name="send"
    value="Get Job Info."
    title="Get results from Tier3 Server"
    />

    Jobs Found:
    <input
    type="text"
    class="revRight"
    name="recCount"
    readonly="readonly"
    value="0"
    size=5
    title="Number of matching jobs found in last request"
    />

    <input
    type="button"
    onclick="sendOOB(33);"
    name="reqAbort"
    value="Abort Request"
    disabled="disabled"
    title="Send an Abort request to the server"
    />
    <br /><br />
    </div>

    <div style="height:90px; font-size: 14px;">
    <select
    name="jobList"
    id="jobList"
    disabled="disabled"
    onfocus="hideQues();"
    onclick="return showDetails()"
    class="greenScreen">
    <option
    id="lovHdr"
    style="color:Black; background-color:Turquoise;"
    >Entry Nbr-|Job Name-------------------------------|Job

    Status-----|Queue Name---------------------|Queue Type|Status----</o
    ption>
    </select>
    </div>
    </form>

    <div style="overflow:auto; height:180px;"><p>
    This is an example of a browser-based, html and JavaScript,
    client interacting with a VMS hosted Application Server in
    a connection-oriented and context-rich Tier3 environment.<br /><br />

    You would have noticed that, when this page was initially displayed,
    you were immediately prompted for your VMS Username and Password.
    Once authorization is successful your credentials, and an accompanying
    Persona, are automatically made available to your 3GL User Action
    Routines each time their Server Process is chosen to perform work on
    behalf of the client. In this example, the user only gets to see those
    Print and Batch jobs that they have privileges to view. You can find
    the corresponding server code for this example (demo_uars.cob) in your
    t3$examples directory.<br /><br />

    Your Tier3 session and server connection are terminated when you change
    web pages or refresh this page.</p></div>
    <hr><br />
    <span class="credits">
    "Tier3" is a registered trademark of Tier3 Software Ltd<br />
    "CornuCopiae" is a trademark of Richard Maher<br /></span>
    <div class="waiting" id="stallMsg"></div>
    <div
    id="queInfo"
    class="floater"
    style="visibility: hidden"
    >

    <form name="queOptions">
    <select name="queList" class="options" onclick="return
    selectQue()"></select>
    </form>
    </div>
    <div
    id="sortBy"
    class="sortPanel"
    >

    <form
    name="sortMenu"
    style="font-size: 14px; margin-bottom: 0px;"
    >

    <div class="sortHead">Sort By</div>

    <input
    type="radio"
    name="sortKey"
    id="r1"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout ="menuMove(event)"
    onmousedown="sortIt(0)"
    />

    <label for="r1"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(0)"
    >Entry Number</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r2"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(1)"
    />

    <label for="r2"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(1)"
    >Job Name</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r3"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(2)"
    />

    <label for="r3"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(2)"
    >Job Status</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r4"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(3)"
    />

    <label for="r4"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(3)"
    >Queue Name</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r5"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(4)"
    />

    <label for="r5"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(4)"
    >Queue Type</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r6"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(5)"
    />

    <label for="r6"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onmousedown="sortIt(5)"
    >Queue Status</label><br />


    <input
    type="radio"
    name="sortKey"
    id="r7"
    checked="checked"
    class="sortButton"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    onclick="document.getJobs.queName.focus()"
    onblur='sortBy.style.visibility="hidden"'

    />
    <label for="r7"
    onmouseover="menuMove(event)"
    onmouseout="menuMove(event)"
    >Exit</label>


    </form>
    </div>
    </body>
    </html>
    Richard Maher, Aug 22, 2007
    #4
  5. Teo

    RobG Guest

    On Aug 22, 9:16 am, "" <>
    wrote:
    > On Aug 21, 2:23 pm, RobG <> wrote:
    >
    > > On Aug 21, 8:46 pm, Teo <> wrote:

    >
    > > > Dear all,

    >
    > > > I would like to sort the elements of a <SELECT> element.

    >
    > > > I tried with

    >
    > > > document.forms.filter_form.server_filter.options.sort(
    > > > function(a,b) {
    > > > // cache values
    > > > var v1 = a.text.toLowerCase();
    > > > var v2 = b.text.toLowerCase();
    > > > // compare
    > > > if (v1 > v2) return(1);
    > > > if (v1 < v2) return(-1);
    > > > return(0);
    > > > }
    > > > );

    >
    > > > but I get the following message:

    >
    > > > Error: document.forms.filter_form.server_filter.options.sort is not a
    > > > function

    >
    > > > document.forms.filter_form.server_filter.options is an array:

    >
    > > Trust the error message, options is not a javascript Array, it is a
    > > DOM HTML collection, which implements the NodeList interface:

    >
    > > <URL:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection

    >
    > > I can

    >
    > > > access and change
    > > > document.forms.filter_form.server_filter.options.length and access the
    > > > elements (e.g., document.forms.filter_form.server_filter.options.

    >
    > > Yes, per the spec.

    >
    > > > Why cannot I also access the sort method?

    >
    > > Because the NodeList interface doesn't implement it, a HTML collection
    > > isn't a javascript Array. Your function should include loading the
    > > options into an array first, then sort them and finally re-position
    > > them in the collection.

    >
    > But the length is writable. It's slightly different than a nodeList,


    In common browsers at least, yes. Whether UAs support setting the
    length in general is implementation dependent.


    > which should raise an exception on setting length. This feature/bug is
    > included for backwards compatibility to NS3, I believe. It's actually
    > quite useful for adding/removing options.
    >
    > You might be able to get away with using sort() in a generic context
    > (sort is an Array generic). Most likely, IE will not run this code,
    > ignoring the spec rec.
    >
    > Array.prototype.sort.call( options, sortMethod );


    Where sortMethod is something like:

    // Expects a an b to be references to option elements
    // whose values are numbers.
    function sortOptionsByValueAsNumber(a, b){

    var sel = a.parentNode;

    if (+a.value < +b.value){
    sel.insertBefore(b, a.nextSibling);
    return -1;
    }

    if (+a.value > +b.value){
    sel.insertBefore(a, b.nextSibling);
    return 1;
    }

    return 0;
    }

    >
    > I haven't actually tried in IE.


    Don't bother, it doesn't work. ;-)


    > Post your results up.
    >
    > This will work in IE:
    >
    > var o = { "1":1, "2":2, "3":3, "0":0, length:3 };
    > Array.prototype.sort.call( o );


    If "work" means does something and doesn't raise any errors when run,
    OK.

    But it seems futile to sort something that is defined as having no
    order and is therefore unsortable in the sense that an array or list
    is sortable. If array-ness is required, the first choice is to use an
    Array.

    If an Array doesn't do the job, the OP should either create a custom
    object that behaves as required, or create functions that act on a
    supplied object and achieve the required result (in this case, the re-
    indexing of an options collection). A plain object can't be relied
    upon to keep its order even if you could prove that it was ever
    sorted.

    Below is a link to an example posted by Martin Honnen in 2000, it's a
    bubble sort and so likely very slow for more than say 100 options, but
    for short lists, it should be fine:

    <URL:
    http://groups.google.com.au/group/c... select options&rnum=1&hl=en#cb6489a4c0b0fcfd
    >


    Matt Kruse's Javascript Toolbox has a more modern version:

    <URL: http://www.mattkruse.com/javascript/selectbox/ >
    <URL: http://www.javascripttoolbox.com/lib/selectbox/documentation.php
    >



    --
    Rob
    RobG, Aug 22, 2007
    #5
  6. RobG wrote:
    > [...] options [...] is a DOM HTML collection,


    It isn't. Unless you mean "DOM HTML" collection, not DOM "HTML collection"
    (HTMLCollection).

    > which implements the NodeList interface:


    It implements the HTMLOptionCollection interface:

    > <URL: http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection


    If HTMLOptionCollection extended anything (here: ExtendedInterface), the IDL
    would look like

    interface HTMLOptionsCollection : ExtendedInterface {
    ...
    }


    PointedEars
    --
    realism: HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness: XHTML 1.1 as application/xhtml+xml
    -- Bjoern Hoehrmann
    Thomas 'PointedEars' Lahn, Aug 22, 2007
    #6
  7. RobG wrote:
    > [...] "" [...] wrote:
    >> On Aug 21, 2:23 pm, RobG <> wrote:
    >>> On Aug 21, 8:46 pm, Teo <> wrote:
    >>>> Error: document.forms.filter_form.server_filter.options.sort is not a
    >>>> function
    >>>> document.forms.filter_form.server_filter.options is an array:
    >>> Trust the error message, options is not a javascript Array, it is a
    >>> DOM HTML collection, which implements the NodeList interface:
    >>> <URL:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection
    >>> I can
    >>>> access and change
    >>>> document.forms.filter_form.server_filter.options.length and access the
    >>>> elements (e.g., document.forms.filter_form.server_filter.options.
    >>> Yes, per the spec.
    >>>> Why cannot I also access the sort method?
    >>> Because the NodeList interface doesn't implement it,


    NodeList is irrelevant here. `options' is NOT a NodeList object.

    >>> a HTML collection isn't a javascript Array. Your function should
    >>> include loading the options into an array first, then sort them and
    >>> finally re-position them in the collection.

    >> But the length is writable. It's slightly different than a nodeList,

    >
    > In common browsers at least, yes. Whether UAs support setting the
    > length in general is implementation dependent.


    Well, they SHOULD, if not even MUST, support that if they implement the
    HTMLOptionsCollection interface for `options'. The `length' attribute
    is not `readonly' per the IDL.


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
    Thomas 'PointedEars' Lahn, Aug 22, 2007
    #7
  8. Teo

    Teo Guest

    On Aug 22, 1:34 am, "Richard Maher" <>
    wrote:
    > > > Why cannot I also access the sort method?

    >
    > > Because the NodeList interface doesn't implement it, a HTML collection
    > > isn't a javascript Array. Your function should include loading the
    > > options into an array first, then sort them and finally re-position
    > > them in the collection.

    >
    > I never new that; but it makes me feel better. I had previously (see below)
    > had to unload an options collection into an array to sort it, purely (or so
    > I thought at the time) to get around the problem of my having a "header" row
    > at option[0]. The fact that the exercise had to be undertaken regardless is
    > strangely comforting.
    >
    > Anyway, FWIW there is an example of just such select-list-sorting below. If
    > you look at the jobList SELECT list you'll see that the onclick event calls
    > the showDetails() function. If the selectedIndex is zero (they clicked on
    > the "header" row) then I first check that there's more than one row to sort
    > and then I pop-up a <div> to ask them what key (select list column) to sort
    > on. (Could this be done with x/y pixel co-ords for the click?) I then unload
    > the options[] collection (except for element [0]) into a JavaScript array
    > and sort it before loading it back into the select-list. (FYI If they
    > clicked on a row other than the "header" I drill-down into a details
    > screen/frame)
    >
    > Hope it helps 'cos (at least to me) it sounds relevant to what you're trying
    > to do. (Sorry to reproduce the whole thing so soon after posting it to
    > another question but cut/pasting would take some time and then I'd probably
    > miss out a bit, or it wouldn't make sense out of context. Either way it's
    > diskspace not trees so just don't print it all :)
    >
    > Cheers Richard Maher
    >
    > PS. The code also contains RobG's suggestion (or my dodgy implementation of
    > it :) of using node-cloning to speed up performance when tearing down a
    > select-list before repopulating it. Thanks again Rob.


    Many thanks to all of you. It's the first time I have to do something
    with Javascript and I understand now that I have to learn a little bit
    more about it :)

    In any case thanks again.

    Matteo
    Teo, Aug 22, 2007
    #8
  9. Teo

    Guest

    On Aug 21, 7:47 pm, RobG <> wrote:
    > On Aug 22, 9:16 am, "" <>
    > wrote:
    >
    > > But the length is writable. It's slightly different than a nodeList,

    >
    > In common browsers at least, yes. Whether UAs support setting the
    > length in general is implementation dependent.
    >


    Not according to the link to:
    http://www.w3.org/TR/DOM-Level-2-HTML/html.html#HTMLOptionsCollection

    interface HTMLOptionsCollection {
    attribute unsigned long length;
    // raises(DOMException) on
    setting

    In reality, implementations let you set the length, which is useful. I
    guess in that sense, it is implementation dependent.

    > > which should raise an exception on setting length. This feature/bug is
    > > included for backwards compatibility to NS3, I believe. It's actually
    > > quite useful for adding/removing options.

    >
    > > You might be able to get away with using sort() in a generic context
    > > (sort is an Array generic). Most likely, IE will not run this code,
    > > ignoring the spec rec.

    >
    > > Array.prototype.sort.call( options, sortMethod );

    >
    > Where sortMethod is something like:
    >
    > // Expects a an b to be references to option elements
    > // whose values are numbers.
    > function sortOptionsByValueAsNumber(a, b){
    >
    > var sel = a.parentNode;
    >
    > if (+a.value < +b.value){
    > sel.insertBefore(b, a.nextSibling);
    > return -1;
    > }
    >
    > if (+a.value > +b.value){
    > sel.insertBefore(a, b.nextSibling);
    > return 1;
    > }
    >
    > return 0;
    >
    > }
    >

    I was thinking along the lines of the original sort function Teo
    provided.

    It would, in that case, require removal of the select from the
    defaultView

    select = select.parentNode.removeChild( select );
    Array.prototype.sort.call( select.options, teoSort );


    > > I haven't actually tried in IE.

    >
    > Don't bother, it doesn't work. ;-)
    >

    I'm utterly shocked. ;)

    <snip>
    >
    > > This will work in IE:

    >
    > > var o = { "1":1, "2":2, "3":3, "0":0, length:3 };
    > > Array.prototype.sort.call( { "1":1, "2":2, "3":3, "0":0, length:3 } );

    >
    > If "work" means does something and doesn't raise any errors when run,
    > OK.
    >

    It works in the sense that it does what it's expected to do, -- that's
    more than just 'something'.

    > But it seems futile to sort something that is defined as having no
    > order and is therefore unsortable in the sense that an array or list
    > is sortable. If array-ness is required, the first choice is to use an
    > Array.
    >

    It's an example just to show that sort() is a generic method.

    But it does actually sort the object; it has potential use. I could
    see creating a data structure from an object. You can't actually
    extend Array in IE. Bummer, huh? So you can create a custom object,
    then create a length property. In the past, I've opted to use a
    composite approach with an internal array, but I think this object-
    with-a-length approach is worth trying out.

    <snip>

    > --
    > Rob
    , Aug 22, 2007
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?iso-8859-1?Q?=22Orlando_D=F6hring=22?=

    [B,IX] = sort(A,...) - Order for sort()-function

    =?iso-8859-1?Q?=22Orlando_D=F6hring=22?=, May 29, 2007, in forum: Python
    Replies:
    0
    Views:
    313
    =?iso-8859-1?Q?=22Orlando_D=F6hring=22?=
    May 29, 2007
  2. Scott
    Replies:
    2
    Views:
    394
    Scott
    Aug 9, 2007
  3. Navin
    Replies:
    1
    Views:
    674
    Ken Schaefer
    Sep 9, 2003
  4. palmiere
    Replies:
    1
    Views:
    388
    Erwin Moller
    Feb 9, 2004
  5. GIMME
    Replies:
    5
    Views:
    178
    Thomas 'PointedEars' Lahn
    Jul 26, 2004
Loading...

Share This Page