Per Sandström
Per Sandström

Reputation: 225

Convert a hierarchical unordered list to a select list using javascript

I want to achieve something similar like the question How to convert unordered list into nicely styled dropdown using jquery?, but with a hierarchical ul list. I want to convert this HTML:

<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About us</a>
        <ul>
            <li><a href="/about/staff">Staff</a></li>
                <ul>
                    <li class="current-page"><a href="/about/staff/john-doe">John Doe</a></li>
                    <li><a href="/about/staff/jane-doe">Jane Doe</a></li>
                </ul>
        </ul>
    </li>
    <li><a href="/products">Products</a>
        <ul>
            <li><a href="/products/games">Games</a>
                <ul>
                    <li><a href="/products/games/xbox">XBOX</a></li>
                    <li><a href="/products/games/ps3">PlayStation 3</a></li>
                    <li><a href="/products/games/ipad">iPad</a></li>
                    <li><a href="/products/games/iphone">iPhone</a></li>
                </ul>
            </li>
            <li><a href="/products/hardware">Hardware</a>
                <ul>
                    <li><a href="/products/hardware/controllers">Controllers</a></li>
                    <li><a href="/products/hardware/memory">Memory units</a></li>
                </ul>
            </li>
            <li><a href="/products/upcoming">Upcoming</a></li>
        </ul>
    </li>
    <li><a href="/contact">Contact us</a></li>
</ul>

To this:

<select>
    <option value="/">Home</option>
    <option value="/about">About us</option>
    <option value="/about/staff">- Staff</option>
    <option value="/about/staff/john-doe" selected>-- John Doe</option>
    <option value="/about/staff/jane-doe">-- Jane Doe</option>
    <option value="/products">Products</option>
    <option value="/products/games">- Games</option>
    <option value="/products/games/xbox">-- XBOX</option>
    <option value="/products/games/ps3">-- PlayStation 3</option>
    <option value="/products/games/ipad">-- iPad</option>
    <option value="/products/games/iphone">-- iPhone</option>
    <option value="/products/hardware">- Hardware</option>
    <option value="/products/hardware/controllers">-- Controllers</option>
    <option value="/products/hardware/memory">-- Memory</option>
    <option value="/products/upcoming">- Upcoming</option>
    <option value="/contact">Contact us</option>
</select>

The class "current-page" on the li should mark the corresponding option in the select as selected. A jQuery as well as vanilla JavaScript would do.

Upvotes: 2

Views: 4903

Answers (1)

Asbj&#248;rn Ulsberg
Asbj&#248;rn Ulsberg

Reputation: 8820

Here's some jQuery code doing what you want. As I don't know where you want the <select> appended, I'm just appending it directly to <body>. There's also an issue of the $('li') selector being too greedy (it will select all <li> elements in the document), but it's easy to fix given the knowledge about the parent elements of the <ul> element you've posted.

(function($) { $(function() {
    var $select = $('<select>')
        .appendTo('body');

    $('li').each(function() {
        var $li    = $(this),
            $a     = $li.find('> a'),
            $p     = $li.parents('li'),
            prefix = new Array($p.length + 1).join('-');

        var $option = $('<option>')
            .text(prefix + ' ' + $a.text())
            .val($a.attr('href'))                       
            .appendTo($select);

        if ($li.hasClass('current-page')) {
            $option.attr('selected', 'selected');
        }
    });
});})(jQuery);

I would also consider using <optgroup> instead of the - prefix as a way of indicating the hierarchy level.

Upvotes: 5

Related Questions