AnApprentice
AnApprentice

Reputation: 110960

How to add a option to a select box in the correct position dynamically?

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

Upvotes: 5

Views: 6317

Answers (6)

Paul Flahr
Paul Flahr

Reputation: 95

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;
}
});

Upvotes: 3

Brendan Nee
Brendan Nee

Reputation: 5353

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);
}

Upvotes: 0

Majid Fouladpour
Majid Fouladpour

Reputation: 30252

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;
  }
});

Upvotes: 0

Jeff B
Jeff B

Reputation: 30099

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/

Upvotes: 0

Selvakumar Arumugam
Selvakumar Arumugam

Reputation: 79830

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;
    }

Upvotes: 1

Nick
Nick

Reputation: 390

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?

Upvotes: 1

Related Questions