I've seen more then a few a few posts on SO which are looking to take a list of links and turning them into a drop-down. I've taken those examples and have not had too much luck applying them to my markup which is a bit different. I need to turn a nested list of radio buttons with labels and convert them into a drop down list with <optgroup>
headings, removing nested radio inputs and labels.
Basically the list of radio buttons Im working with is a wildly out of control and a clean drop down list would be much better usability and screen real estate. Once I handle the conversion, the plan is to hide the original radio button set, and then map the user drop-down selection to the corresponding radio buttons to be process on submission of the form. But first I need to generate the drop-down list . . .
Here is a simplified sample of the starting markup:
<ul>
<li>
<label><input type="radio">USA</label>
<ul class="children">
<li>
<label><input type="radio" >Northeast</label>
<ul class="children">
<li>
<label><input itype="radio">Mid-Atlantic</label>
</li>
<li>
<label><input type="radio">New England</label>
</li>
</ul>
</li>
<li>
<label><input type="radio">South</label>
</li>
<li>
<label><input type="radio">West</label>
</li>
</ul>
</li>
<li>
<label><input type="radio" checked="checked">No Venue Region</label>
</li>
</ul>
Im trying to convert the above to the following:
<select>
<optgroup label="USA">
<optgroup>Northeast</option>
<option>Mid-Atlantic</option>
<option>New England</option>
<optgroup>
<option>South</option>
<option>West</option>
</optgroup>
<option>No Region</option>
</select>
You might notice that the top level <ul>
in the first example, also has a radio button associated with it –– but this is not desired as we want the user to be as precise a possible in their selection. These should have been headings, but unfortunately I have no control of what's generated.
They type of solution I favour is to use a function to process the existing markup into a new entity which I can then append to the parent DOM element after hiding the original.
In this SO thread @Enki offers a solution with this approach, but I've not been able to apply it, as I just cant quite understand how its iterating though all the elements. His solution goes like this:
function sitemapCycle(){
if(typeof(sitemapNode)==="undefined") sitemapNode= $("#sitemap");
if($(this).find("ul").length)
{
sitemapNode= $(sitemapNode).append('<optgroup label="'+$(this).children().first().text()+'" />').children().last();
$(this).find("ul li").each(sitemapCycle);
sitemapNode= $(sitemapNode).parent();
}
else
{
$(sitemapNode).append('<option value="'+$(this).children().attr("href")+'">'+$(this).text()+'</option>');
}
}
var sitemapNode;
$("#sitemap").removeAttr("id").after('<select id="sitemap" />').children().each(sitemapCycle).parent().remove();
The closest I've been able to get, which doesn't use @Enki's approach, and doesn't create optgroup top levels and is truly incomplete is this:
$(function() {
$('#venue-regionchecklist').each(function() {
$(this).find('label').each(function() {
var cnt = $(this).contents();
$(this).replaceWith(cnt);
});
var $select = $('<select />');
$(this).find('li').each(function() {
var $option = $('<option />');
$(this).html($(this).html());
$option.attr('id', $(this).attr('id')).html($(this).html());
$select.append($option);
});
$(this).replaceWith($select);
});
});
Here is a unsimplified sample of the radio list if anyone wants to take a whack at it. I would love to know how you would approach this kind of problem.