Solved

need help populating select list from nested unordered list

Posted on 2004-07-30
5
495 Views
Last Modified: 2008-02-26
I am trying to make an accessible site that has several select list that are populated dynamically when the previous list is selected. I decided that I would send all the options as a nested unordered list and then use javascript to create and populate two drop down list from the unordered list, and then hide the list. This way if there is no javascript or a screen reader the unordered list would serve to replace the drop downs.
This is what I have come up with so far. The problem I am having is that the select options have no value or text I want to use the id's of the li for the value and the text of the nested anchor tags as the text of the select.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
      <title>Unordered List Select Box Script</title>
      <script language="javascript">
            

            //Create the category select list from the unordered list
            function loadCategorySelect(){
                  if(isCapable()==true){
                        var list= document.getElementById('catGrantList');
                        var option;
                        var listElem;
                        var select = document.createElement('select');
                        select.setAttribute('name', 'category');
                        select.setAttribute('onChange','loadGranteeSelect()');
                        var children= list.childNodes;
                        var i=0;
                        for( i=0; i < children.length; i++){
                              listElem= children[i];
                              if(listElem.tagName=='li'){
                                    option= document.createElement('option');
                                    option.value=listElem.getAttribute(id);
                                    option.text=listElem.childNodes[0].text;
                                    select.add(option);
                              }
                        }
                        var catPos= document.getElementById('catSelect');
                        catPos.appendChild(select);
                  }                  
            }      

            //Create the GRantee select box from the unordered list            
            function loadGrnateeSelect(){
                  var label= document.getElementById('grantLabel');
                  label.innertext='Select a Grantee';
                  

            }

            //hides the unordered list from javscript enabled browsers
            function hideList(){
                  if(isCapable() == true){
                        var obj= document.getElementById('catGrantList');
                        obj.style.visibility='hidden';
                        return true;
                  }
            }
            
            //Check for browser DOM Compatibility
            function isCapable(){
                  if (parseInt(navigator.appVersion) >= 5 || navigator.appVersion.indexOf["MSIE 5"] != -1)
                  {
                        return true;
                  }
                  else{
                        return false;
                  }
            }
      </script>
</head>
            
<body>


<div>
      <span>Choose a Category</span><span id="catSelect"></span>
</div>
<div>
      <span id="grantLabel"></span><span id="grantSelect"></span>
</div>


<ul id="catGrantList">Category and Grantee Options
      <li id="1"><a href="somepage.jsp?catid=1">ACF Regions</a>
            <ul id="acf">
                  <li id="131"><a href="Somepage.jsp?catid=1&grantee=131">Region 1</a></li>
                  <li id="132"><a href="Somepage.jsp?catid=1&grantee=132">Region 2</a></li>
                  <li id="141"><a href="Somepage.jsp?catid=1&grantee=141">Region 3</a></li>
                  <li id="151"><a href="Somepage.jsp?catid=1&grantee=151">Region 4</a></li>
                  <li id="161"><a href="Somepage.jsp?catid=1&grantee=161">Region 5</a></li>
            </ul>
      </li>
      <li id="2">Miscellaneous
            <ul id="misc">
                  <li id="231">Misc 1</li>
                  <li id="241">Misc 2</li>
                  <li id="251">Misc 3</li>
                  <li id="261">Misc 4</li>
                  <li id="271">Misc 5</li>
                  <li id="281">Misc 6</li>
            </ul>
      </li>
      <li id="3">tribes
            <ul id="tribes">
                  <li id="23">Tribe 1</li>
                  <li id="42">Tribe 2</li>
                  <li id="51">Tribe 3</li>
                  <li id="63">Tribe 4</li>
                  <li id="44">Tribe 5</li>
                  <li id="55">Tribe 6</li>
            </ul>
      </li>
</ul>
<script type="text/javascript">
      loadCategorySelect();
      hideList();
</script>

</body>
</html>
0
Comment
Question by:haobaba1
  • 3
  • 2
5 Comments
 
LVL 19

Expert Comment

by:dakyd
ID: 11681803
How about this?  You can add more elements to your list as you please, with the only requirement being that you give the top level <li>'s (ACF Regions, Miscellaneous, tribes, etc.) id's that are numbers.  Just continue numbering them as before.  Hope that helps.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Unordered List Select Box Script</title>
<script type="text/javascript">          
var topLevel = new Array();
var drillDown = new Array();

function init()
{
  var lis = document.getElementById("catGrantList").childNodes;
  var ctr = 0;
  for (var i = 0; i < lis.length; i ++)
  {
    // assign top level first
    if (lis[i].tagName && lis[i].tagName.toLowerCase() == "li")
    {
      if (lis[i].childNodes[0].data)
        topLevel[ctr] = new Array(lis[i].childNodes[0].data, lis[i].id);
      else if (lis[i].childNodes[0].text)
        topLevel[ctr] = new Array(lis[i].childNodes[0].text, lis[i].id);
      else
        topLevel[ctr] = new Array(lis[i].childNodes[0].innerHTML, lis[i].id);

      // now assign options
      var inner = lis[i].getElementsByTagName("li");
      drillDown[ctr] = new Array();
      for (var j = 0; j < inner.length; j ++)
      {
        if (inner[j].childNodes[0].data)
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].data, inner[j].id);
        else if (inner[j].childNodes[0].text)
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].text, inner[j].id);
        else
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].innerHTML, inner[j].id);
      }
      ctr ++;
    }
  }
  if (isCapable())
  {
    loadCategorySelect();
    hideList();
  }
}

//Create the category select list from the unordered list
function loadCategorySelect()
{
  if(isCapable())
  {
    var theSel = document.getElementById("catSel");
    for (var i = 0; i < topLevel.length; i ++)
      theSel.options[theSel.options.length] = new Option(topLevel[i][0], topLevel[i][1]);
    document.getElementById("cat").style.display = "block";
    return true;
  }
  else
    return false;              
}    

//Create the GRantee select box from the unordered list          
function loadGranteeSelect(){
  if (isCapable())
  {
    var oldSel = document.getElementById("catSel");
    var index = parseInt(oldSel.options[oldSel.options.selectedIndex].value) - 1;
    var theSel = document.getElementById("grantSel");
    for (var i = 0; i < theSel.options.length; i ++)
      theSel.options[i] = null;
    for (var i = 0; i < drillDown[index].length; i ++)
      theSel.options[i] = new Option(drillDown[index][i][0], drillDown[index][i][1]);
    document.getElementById("grantee").style.display = "block";
    return true;
  }
  return false;
}

//hides the unordered list from javscript enabled browsers
function hideList(){
  if(isCapable()){
    var obj= document.getElementById("catGrantList");
    obj.style.display = "none";
    return true;
  }
}
         
//Check for browser DOM Compatibility
function isCapable(){
  if (parseInt(navigator.appVersion) >= 5 || navigator.appVersion.indexOf["MSIE 5"] != -1)
    return true;
  else
    return false;
}
</script>
</head>
         
<body onload="init()">

<div id="cat" style="display: none">
     <span>Choose a Category</span>
     <span><select id="catSel" onchange="loadGranteeSelect()"></select></span>
</div>
<div id="grantee" style="display: none">
     <span>Select a Grantee </span>
     <span><select id="grantSel"></select></span>
</div>


<ul id="catGrantList">Category and Grantee Options
     <li id="1"><a href="somepage.jsp?catid=1">ACF Regions</a>
          <ul id="acf">
               <li id="131"><a href="Somepage.jsp?catid=1&grantee=131">Region 1</a></li>
               <li id="132"><a href="Somepage.jsp?catid=1&grantee=132">Region 2</a></li>
               <li id="141"><a href="Somepage.jsp?catid=1&grantee=141">Region 3</a></li>
               <li id="151"><a href="Somepage.jsp?catid=1&grantee=151">Region 4</a></li>
               <li id="161"><a href="Somepage.jsp?catid=1&grantee=161">Region 5</a></li>
          </ul>
     </li>
     <li id="2">Miscellaneous
          <ul id="misc">
               <li id="231">Misc 1</li>
               <li id="241">Misc 2</li>
               <li id="251">Misc 3</li>
               <li id="261">Misc 4</li>
               <li id="271">Misc 5</li>
               <li id="281">Misc 6</li>
          </ul>
     </li>
     <li id="3">tribes
          <ul id="tribes">
               <li id="23">Tribe 1</li>
               <li id="42">Tribe 2</li>
               <li id="51">Tribe 3</li>
               <li id="63">Tribe 4</li>
               <li id="44">Tribe 5</li>
               <li id="55">Tribe 6</li>
          </ul>
     </li>
</ul>
</body>
</html>
0
 
LVL 3

Author Comment

by:haobaba1
ID: 11693765
This works great I was just wondering if you could clarify the code for me a little. I have increased the point value as well. What I would like to know is when is it appropriate to access innerNodes.data as opposed to innerNodes.text as opposed to innerNodes.innerHtml? I would just like to know which tags in the document each of these different access methods are used for.

One other thing. I would like to add the select boxes to the dom at run time this way a blind user would not be slowed down by the listing of the empty selects. If there is a better way to prevent this than adding more complexity to the code I am very open to this.

Thanks alot.
0
 
LVL 19

Accepted Solution

by:
dakyd earned 200 total points
ID: 11694044
Sure thing, code clarification first... the first child of your outer-most <li> tags can be one of two things, either <a> (e.g. the ACF Regions category) or plain old text (e.g. Miscellaneous).  If you have plain old text, the DOM will treat it like a textNode, so you use innerNodes.data.  If you've got <a> and you're using a browser that's fairly standards-compliant, you can use innerNodes.text to get the text you want.  That doesn't work for all browsers (IE, for example), so the last resort is to use innerNodes.innerHTML, which literally returns the text between <a> and </a>.  Most browsers do support innerHTML now, as far as I know, so it should be a good safety net.

As for the select boxes, they're hidden until runtime.  It makes the code a little cleaner this way, and unless isCapable() returns true, they'll stay hidden.  Unless I don't understand you, it should be a viable alternative.  To illustrate what I mean, take out this part: onload="init()" from the <body> tag.  The select tags are still a part of your page, but they won't render.  Put the onload back in, and the selects show up again.

If you have any more questions, let me know.  Hope that helps.
0
 
LVL 19

Expert Comment

by:dakyd
ID: 11694661
Hm ... turns out that JAWS doesn't always ignore elements with display="none".  And from what I can tell, JAWS has a fairly sizable share of the screen reader market.  So here's the tweak you asked for, elements are created at runtime.  Hope that helps.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Unordered List Select Box Script</title>
<script type="text/javascript">          
var topLevel = new Array();
var drillDown = new Array();

function init()
{
  var lis = document.getElementById("catGrantList").childNodes;
  var ctr = 0;
  for (var i = 0; i < lis.length; i ++)
  {
    // assign top level first
    if (lis[i].tagName && lis[i].tagName.toLowerCase() == "li")
    {
      if (lis[i].childNodes[0].data)
        topLevel[ctr] = new Array(lis[i].childNodes[0].data, lis[i].id);
      else if (lis[i].childNodes[0].text)
        topLevel[ctr] = new Array(lis[i].childNodes[0].text, lis[i].id);
      else
        topLevel[ctr] = new Array(lis[i].childNodes[0].innerHTML, lis[i].id);

      // now assign options
      var inner = lis[i].getElementsByTagName("li");
      drillDown[ctr] = new Array();
      for (var j = 0; j < inner.length; j ++)
      {
        if (inner[j].childNodes[0].data)
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].data, inner[j].id);
        else if (inner[j].childNodes[0].text)
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].text, inner[j].id);
        else
          drillDown[ctr][j] = new Array(inner[j].childNodes[0].innerHTML, inner[j].id);
      }
      ctr ++;
    }
  }

  if (isCapable())
  {
    loadCategorySelect();
    hideList();
  }
}

//Create the category select list from the unordered list
function loadCategorySelect()
{
  if(isCapable())
  {
    // create the elements in the DOM
    var theSel = document.createElement("select");
    theSel.id = "catSel";
    theSel.onchange = loadGranteeSelect;
    document.getElementById("cat").appendChild(theSel);

    for (var i = 0; i < topLevel.length; i ++)
      theSel.options[theSel.options.length] = new Option(topLevel[i][0], topLevel[i][1]);
    document.getElementById("cat").style.display = "block";
    return true;
  }
  else
    return false;              
}    

//Create the GRantee select box from the unordered list          
function loadGranteeSelect(){
  if (isCapable())
  {
    // create the elements in the DOM
    var theLabel = document.getElementById("granteeLabel");
    theLabel.innerHTML = "Select a Grantee ";
    var theSel = document.getElementById("grantSel");
    if (theSel)
      document.getElementById("grantee").removeChild(theSel);
    theSel = document.createElement("select");
    theSel.id = "grantSel";
    document.getElementById("grantee").appendChild(theSel);    

    var oldSel = document.getElementById("catSel");
    var index = parseInt(oldSel.options[oldSel.options.selectedIndex].value) - 1;
    for (var i = 0; i < theSel.options.length; i ++)
      theSel.options[i] = null;
    for (var i = 0; i < drillDown[index].length; i ++)
      theSel.options[i] = new Option(drillDown[index][i][0], drillDown[index][i][1]);
    document.getElementById("grantee").style.display = "block";
    return true;
  }
  return false;
}

//hides the unordered list from javscript enabled browsers
function hideList(){
  if(isCapable()){
    var obj= document.getElementById("catGrantList");
    obj.style.display = "none";
    return true;
  }
}
         
//Check for browser DOM Compatibility
function isCapable(){
  if (parseInt(navigator.appVersion) >= 5 || navigator.appVersion.indexOf["MSIE 5"] != -1)
    return true;
  else
    return false;
}
</script>
</head>
         
<body onload="init()">

<div id="cat" style="display: none">
     <span>Choose a Category</span>
</div>
<div id="grantee" style="display: none">
     <span id="granteeLabel"></span>
</div>


<ul id="catGrantList">Category and Grantee Options
     <li id="1"><a href="somepage.jsp?catid=1">ACF Regions</a>
          <ul id="acf">
               <li id="131"><a href="Somepage.jsp?catid=1&grantee=131">Region 1</a></li>
               <li id="132"><a href="Somepage.jsp?catid=1&grantee=132">Region 2</a></li>
               <li id="141"><a href="Somepage.jsp?catid=1&grantee=141">Region 3</a></li>
               <li id="151"><a href="Somepage.jsp?catid=1&grantee=151">Region 4</a></li>
               <li id="161"><a href="Somepage.jsp?catid=1&grantee=161">Region 5</a></li>
          </ul>
     </li>
     <li id="2">Miscellaneous
          <ul id="misc">
               <li id="231">Misc 1</li>
               <li id="241">Misc 2</li>
               <li id="251">Misc 3</li>
               <li id="261">Misc 4</li>
               <li id="271">Misc 5</li>
               <li id="281">Misc 6</li>
          </ul>
     </li>
     <li id="3">tribes
          <ul id="tribes">
               <li id="23">Tribe 1</li>
               <li id="42">Tribe 2</li>
               <li id="51">Tribe 3</li>
               <li id="63">Tribe 4</li>
               <li id="44">Tribe 5</li>
               <li id="55">Tribe 6</li>
          </ul>
     </li>
</ul>
</body>
</html>
0
 
LVL 3

Author Comment

by:haobaba1
ID: 11696353
Thanks a lot for the help and the clarifications.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Today I would like to talk about localizing (Internationalization) JavaScript applications. Introduction When creating an application that is going to be used by many people around the globe, it is important to remember that not everyone speak…
JavaScript can be used in a browser to change parts of a webpage dynamically. It begins with the following pattern: If condition W is true, do thing X to target Y after event Z. Below are some tips and tricks to help you get started with JavaScript …
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now