4

Given the select box below. I want to be able to dynamically add a new option.

<select id="user_department_id" name="user[department_id]">

 <option value=""> </option>

 <option value="9">AAAAA</option>
 <option value="11">BBBBB</option>
 <option value="10">G</option>
 <option value="12">Z</option>

 <option value="">--</option>
 <option value="add">Add a New</option>
</select>

I have been using the following to add a new option:

$('#user_department_id')
    .prepend($("<option></option>")
    .attr("value",data.id)
    .text(data.title)
);

The problem here is that it is position unnaturally, it's above the empty placeholder option and not sorted alphabetically. Is there a magic way to append a new select option in the correct place?

Thanks

AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

6 Answers6

3

This inserts a new option value into (assuming it is already sorted)

$('#yourselectID option').each(function()
{
  var option = $(this).text();
  option = option.toLowerCase(); 
  var test = option.toLowerCase();
  if ( option > test) 
{
    $(this).before('<option value="'+test+'">' + test+ '</option>');
    return false;
}
});
Paul Flahr
  • 95
  • 12
  • 1
    Beware of this snippet: the option won't be inserted if it should be inserted as last element. – Claros Jun 19 '19 at 15:11
1

I think you can use .after('blah') with the selector you described.

for example:

$('#user_department_id option[value="12"]').after('<option value="13">Q</option>')

is that of any use?

Nick
  • 390
  • 2
  • 12
  • Oh, after reading I see the problem is more about sorting? Please disregard. – Nick Mar 28 '12 at 22:41
  • If the sort is based on the option text, just treat it as an insertion sort, iterating over the options and checking the text of each option; then, use .after(...) as @Nick mentioned. – RMorrisey Mar 28 '12 at 22:53
1

As mentioned in my comment, you can remove the option that you don't want to sort and then add them back.

Note: The below will work in your case because you want the -- and Add New at the end.

DEMO

    var selElem = document.getElementById('user_department_id')
    var tmpAry = [];
    var igOpt = [];
    for (var i = 0; i < selElem.options.length; i++) {

        if ($(selElem.options[i]).hasClass('ig')) {
            igOpt.push([selElem.options[i].text,
                        selElem.options[i].value]);
            continue;
        }
        tmpAry[i] = new Array();
        tmpAry[i][0] = selElem.options[i].text;
        tmpAry[i][1] = selElem.options[i].value;
    }
    tmpAry.sort();
    //merge with ignored options
    tmpAry = tmpAry.concat(igOpt);
    //remove options
    $(selElem).empty();

    for (var i = 0; i < tmpAry.length; i++) {
        var op = new Option(tmpAry[i][0], tmpAry[i][1]);
        selElem.options[i] = op;
    }
Selvakumar Arumugam
  • 79,297
  • 15
  • 120
  • 134
0

You can use underscore's sortedIndex to figure out where to insert the item and then jquery's after function to insert it at that position. This is assuming you want to sort by option text alphabetically:

var option = '<option value="' + data.id + '">' + data.title + '</option>';
var index = _.sortedIndex($('#user_department_id option'), option, function(item) {
  return $(item).text();
});
if(index === 0) {
  $('#user_department_id').prepend(option);
} else {
  $('#user_department_id option').eq(index - 1).after(option);
}
Brendan Nee
  • 5,087
  • 2
  • 33
  • 32
0

Not very elegant, but this should do:

$('#user_department_id option').each(function() {
  if(this.text > data.title) {
    $(this).before('<option value="' + data.id + '">' + data.title + '</option>');
    return false;
  }
});
Majid Fouladpour
  • 29,356
  • 21
  • 76
  • 127
0

Keep your options in an array of objects and generate your select from that object. Then add your new items to that array and regenerate your select.

$(function() {
    // Any options always on the top
    var topOptions = '<option value=""> </option>';

    // Your middle, sorted options
    var options = [{val: 9, text: "AAAAA"}, {val: 11, text: "BBBBB"},{val: 10, text: "G"},{val: 12, text: "Z"}];

    // Any options always on the bottom
    var bottomOptions = '<option value="">--</option><option value="add">Add a New</option>';

    // Function to populate the select options from above data
    function populateOptions(element, options) {
        // Sort options
        options = options.sort(function(a, b) {
            return a.text.toLowerCase() > b.text.toLowerCase();
        });

        $(element).html('').append(topOptions);
        for (var i = 0; i < options.length; i++) {
            $('<option>').attr("value", options[i].val).text(options[i].text).appendTo($(element));
        }
        $(element).append(bottomOptions);
    }

    // Start by populating the select
    populateOptions('#user_department_id', options);

    // Add and repopulate when add requested
    $('#user_department_id').on('change', function() {
        if ($(this).val() == "add") {
            // Add option to list
            options.push({val: data.id, text: data.text});

            // Repopulate select
            populateOptions(this, options);

            // Select the new item
            $(this).val(data.id);
        }
    });
});

Demo: http://jsfiddle.net/kfC3S/

Jeff B
  • 29,943
  • 7
  • 61
  • 90