jquery convert nested list of radio buttons to dropdown with optgroup headings

大憨熊 提交于 2019-12-11 19:48:04

问题


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.


回答1:


Cheers mate!

I believe recursivity can be of help here:

function buildDropDownFromUL(CurrentUL, level) {
   var dropDownHTML = "";
   CurrentUL.children("li").each(function () { // Cycle through all LI elements
      if ($(this).children("ul").length == 0) {
         // There is no UL element in this LI so it means LI is a selectable option
         dropDownHTML = dropDownHTML + "<option value='" + $(this).children("label").children("input").attr("value") + "'>" + NBSPs(level) + $(this).children("label").text() + "</option>";
      } else {
         // There is a UL in the LI so it means the LABEL in the current LI is a OPTGROUP 
         // and the UL should be again processed
         dropDownHTML = dropDownHTML + "<optgroup label='" + NBSPs(level) + $(this).children("label").text() + "'>" + "</optgroup>" + buildDropDownFromUL($(this).children("ul"), level + 1);
      }
   });
   return dropDownHTML + "<optgroup label='&nbsp;'></optgroup>";
}

There is something to watch for: the function assumes that if a given LI element contains only a LABEL element (and no UL element) then that LABEL is a selectable option and if the LI contains a LABEL and a UL then the LABEL is a option group.

And here is the the Fiddle

I hope it helps!



来源:https://stackoverflow.com/questions/19214051/jquery-convert-nested-list-of-radio-buttons-to-dropdown-with-optgroup-headings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!