Link to home
Start Free TrialLog in
Avatar of haobaba1
haobaba1

asked on

need help populating select list from nested unordered list

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>
Avatar of dakyd
dakyd

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>
Avatar of haobaba1

ASKER

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.
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
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>
Thanks a lot for the help and the clarifications.