Jitendra Vyas
Jitendra Vyas

Reputation: 152677

How to convert unordered list into nicely styled <select> dropdown using jquery?

How do I convert an unordered list in this format

<ul class="selectdropdown">
    <li><a href="one.html" target="_blank">one</a></li>
    <li><a href="two.html" target="_blank">two</a></li>
    <li><a href="three.html" target="_blank">three</a></li>
    <li><a href="four.html" target="_blank">four</a></li>
    <li><a href="five.html" target="_blank">five</a></li>
    <li><a href="six.html" target="_blank">six</a></li>
    <li><a href="seven.html" target="_blank">seven</a></li>
</ul>

into a dropdown in this format

<select>
    <option value="one.html" target="_blank">one</option>
    <option value="two.html" target="_blank">two</option>
    <option value="three.html" target="_blank">three</option>
    <option value="four.html" target="_blank">four</option>
    <option value="five.html" target="_blank">five</option>
    <option value="six.html" target="_blank">six</option>
    <option value="seven.html" target="_blank">seven</option>
</select>

using jQuery?

Edit: When selecting an entry from the select/dropdown the link should open in a new window or tab automatically. I also want to able to style it like: http://www.dfc-e.com/metiers/multimedia/opensource/jqtransform/

Upvotes: 20

Views: 52892

Answers (6)

Jesse Nickles
Jesse Nickles

Reputation: 1839

I found this gorgeous CodePen from @nuckecy for anyone interested:

https://codepen.io/nuckecy/pen/ErPqQm

$(".select").click(function() {
  var is_open = $(this).hasClass("open");
  if (is_open) {
    $(this).removeClass("open");
  } else {
    $(this).addClass("open");
  }
});

$(".select li").click(function() {

  var selected_value = $(this).html();
  var first_li = $(".select li:first-child").html();

  $(".select li:first-child").html(selected_value);
  $(this).html(first_li);

});

$(document).mouseup(function(event) {

  var target = event.target;
  var select = $(".select");

  if (!select.is(target) && select.has(target).length === 0) {
    select.removeClass("open");
  }

});

His default CSS rules:

.select li {
  display: none;
  cursor: pointer;
  padding: 5px 10px;
  border-top: 1px solid black;
  min-width: 150px;
}

.select li:first-child {
  display: block;
  border-top: 0px;
}

.select {
  border: 1px solid black;
  display: inline-block;
  padding: 0;
  border-radius: 4px;
  position: relative;
}

.select li:hover {
  background-color: #ddd;
}

.select li:first-child:hover {
  background-color: transparent;
}

.select.open li {
  display: block;
}

.select span:before {
  position: absolute;
  top: 5px;
  right: 15px;
  content: "\2193";
}

.select.open span:before {
  content: "\2191";
}

Upvotes: 0

quAnton
quAnton

Reputation: 786

I have recently created a solution where the ul transformed, mimics nearly completely the select.

It has in adition a search for the options of the select and supports the active state. Just add a class with name active and that option will be selected.

It handles the keyboard navigation.

Take a look at the code here: GitHub Code

And a live example here: Code Example

The unordered list must be in the form:

<ul id="...">
  <li><a href="...">...</a></li>
  <li><a href="...">...</a></li>
  <li><a class="active" href="...">...</a></li>
  ...
</ul>

To convert the ul to select just call:

$(window).on("load resize", function() {
  ulToSelect($("ul#id"), 767);
});

Where #id is an id for the unordered list and 767 is the minimum width of the window for the convertion to take place. This is very useful if you want the convertion to take place only for mobile or tablet.

Upvotes: 0

czarchaic
czarchaic

Reputation: 6318

$('ul.selectdropdown').each(function() {
    var select = $(document.createElement('select')).insertBefore($(this).hide());
    $('>li a', this).each(function() {
        var a = $(this).click(function() {
            if ($(this).attr('target')==='_blank') {
                window.open(this.href);
            }
            else {
                window.location.href = this.href;
            }
        }),
        option = $(document.createElement('option')).appendTo(select).val(this.href).html($(this).html()).click(function() {
            a.click();
        });
    });
});

In reply to your last comment, I modified it a little bit but haven't tested it. Let me know.

$('ul.selectdropdown').each(function() {
    var list = $(this), select = $(document.createElement('select')).insertBefore($(this).hide());

    $('>li a', this).each(function() {
        var target = $(this).attr('target'),
        option = $(document.createElement('option'))
            .appendTo(select)
            .val(this.href)
            .html($(this).html())
            .click(function(){
                if(target==='_blank') {
                    window.open($(this).val());
                }
                else {
                    window.location.href = $(this).val();
                }
            });
    });
    list.remove();
});

Upvotes: 16

Mon
Mon

Reputation: 86

Thank you all for posting the codes. My scenario is similar but my situation is for Responsiveness that for x-size it would switch to a dropdown list, then if not x-size, using csswatch to check for the "display" properties of an element that has certain amount of width set to it (eg: 740px). Thought I share this solution for anyone who is interested. This is what I have combined with Tatu' codes. Instead of replacing the html, I created then hide the new html then only add them when necessary:

var $list = $('ul.list');
(listFunc = function(display){

    //Less than x-size turns it into a dropdown list
    if(display == 'block'){
        $list.hide();
        if($('.sels').length){
            $('.sels').show();
        } else {
            var $select = $('<select class="sels" />');

            $list.find('a').each(function() {
                var $option = $('<option />');
                $option.attr('value', $(this).attr('href')).html($(this).html());
                $select.append($option);
            });

            $select.insertAfter($list);

            $('.sels').on('change', function(){
                window.location = this.value;
            });
        }
    } else {
        $('.sels').hide();
        $list.show();
    }
})(element.css('display'));
element.csswatch({
    props: 'display'
}).on('css-change', function (event, change) {
    return listFunc(change.display);
});

Upvotes: 0

Radim
Radim

Reputation: 21

This solution is working also in IE and working with selected item (in anchor tag).

$('ul.selectdropdown').each(function(){
var list=$(this),
    select=$(document.createElement('select')).insertBefore($(this).hide()).change(function(){
  window.location.href=$(this).val();
});
$('>li a', this).each(function(){
  var option=$(document.createElement('option'))
   .appendTo(select)
   .val(this.href)
   .html($(this).html());
  if($(this).attr('class') === 'selected'){
    option.attr('selected','selected');
  }
});
list.remove();
});

Upvotes: 2

Tatu Ulmanen
Tatu Ulmanen

Reputation: 124768

$(function() {
    $('ul.selectdropdown').each(function() {
        var $select = $('<select />');

        $(this).find('a').each(function() {
            var $option = $('<option />');
            $option.attr('value', $(this).attr('href')).html($(this).html());
            $select.append($option);
        });

        $(this).replaceWith($select);
    });
});

EDIT

As with any jQuery code you want to run on page load, you have to wrap it inside $(document).ready(function() { ... }); block, or inside it's shorter version $(function() { ... });. I updated the function to show this.

EDIT

There was a bug in my code also, tried to take href from the li element.

Upvotes: 21

Related Questions