key2starz
key2starz

Reputation: 757

Adding optgroups dynamically using jQuery

<select id="myElement" multiple="multiple">
  <option value="1">Category Type</option>
  <option value="158">itemOne</option>
  <option value="157">itemTwo</option>
  <option value="7">My Type</option>
  <option value="20">itemThree</option>
  <option value="21">itemFour</option>
  <option value="22">itemFive</option>
  <option value="8">Category Yet Another</option>
  <option value="31">itemCheese</option>
  <option value="32">itemBrain</option>
</select>

I need to dynamically convert this so that "Category" options (anything that doesn't start with "item") is an optgroup, wrapping whaterver comes after it until the next Category option, so the above would end up looking like:

<select id="myElement" multiple="multiple">
  <optGroup label="Category Type">
    <option value="158">One</option>
    <option value="157">Two</option>
  </optGroup>
  <optGroup label="My Type">
    <option value="20">Three</option>
    <option value="21">Four</option>
    <option value="22">Five</option>
  </optGroup>
  <optGroup label="Category Yet Another">
    <option value="31">Cheese</option>
    <option value="32">Brain</option>
  </optGroup>
</select>

How can I iterate over this and change values to acheive the desired effect using jQuery?

Upvotes: 11

Views: 30246

Answers (4)

Michał Miszczyszyn
Michał Miszczyszyn

Reputation: 12701

You have to iterate over the option elements and group them based on their contents. Using jQuery makes it way easier than just pure DOM API:

http://jsfiddle.net/kpykoahe/2/

$(document).ready(() => {
    const $cont = $('select');
    $('option').each((idx, el) => {
        const $el = $(el);
        if ($el.text().startsWith('item')) {
            $cont.find('optgroup').last().append($el);
            $el.text($el.text().substr(4));
        } else {
            $('<optgroup/>').attr('label', $el.text()).appendTo($cont);
            $el.remove();
        }
    });
});

Upvotes: 20

Parth Desai
Parth Desai

Reputation: 74

$.each(data, function () {

    if (prevGroupName.indexOf(this.Group.Name) == -1) {
        $prevGroup = $('<optgroup />').prop('label', this.Group.Name).appendTo('#ConfigurationId');
    } else {
        $prevGroup = $("optgroup[label='" + this.Group.Name + "']");
    }
    $("<option />").val(this.Value).text(this.Text).appendTo($prevGroup);
    prevGroupName.push(this.Group.Name);
});

Upvotes: 2

webdeveloper
webdeveloper

Reputation: 17288

My implementation:

$(function(){
    var target = $('#target'),
        optGroup;

    function strStartsWith(str, prefix) {
        return str.indexOf(prefix) === 0;
    }

    $('#myElement').find('option').each(function(){
        var elm = $(this).clone();
        if(strStartsWith(elm.text(), 'item'))
        {
            elm.text(elm.text().substr(4));
            if(optGroup) optGroup.append(elm);
        }
        else
        {
            optGroup = $('<optgroup>').attr('label', elm.text());
            target.append(optGroup);
        }
    });
});

Demo: http://jsfiddle.net/HUHRz/1/

Upvotes: 2

Fr&#233;d&#233;ric Hamidi
Fr&#233;d&#233;ric Hamidi

Reputation: 262919

You can use filter() to match the <option> elements that will become groups. Then, you can iterate over them and call nextUntil() on the same element set to match the subsequent options (as nextUntil() will stop when it encounters a member of the set, i.e. the next option that should become a group).

From there, you can use wrapAll() on these <option> elements to create their <optgroup> element, then call remove() on the <option> element that just became a group. Something like:

var $groups = $("#myElement option").filter(function() {
    return $(this).text().indexOf("item") != 0;
});
$groups.each(function() {
    var $this = $(this);
    $this.nextUntil($groups).wrapAll($("<optgroup>", {
        label: $this.text()
    })).end().remove();
});

You can see the results in this fiddle.

Upvotes: 6

Related Questions