Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically appended select menu with 1st option disabled automatically selects 2nd option

I have hit a weird case where, to the best of my knowledge, two things that should act the same behave quite differently.

If I have two select menus on a page, one static menu hardcoded in the HTML and one appended to the body at runtime with JQuery. I then disable the first option in both select menus. When displayed both menus have their first options disabled as expected, however the dynamically appended menu has automatically set the value to the second option while the static menu still has the first selected.

http://jsfiddle.net/hm3xgkLg/1/

HTML:

<select class="dropMenu">
  <option value="1">First</option>
  <option value="2">Second</option>
  <option value="3">Third</option>
  <option value="4">fourth</option>
</select>

Javascript:

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function() {
   sel.append($("<option>").attr('value',this.val).text(this.text));
 });
$('.dropMenu option:nth-child(1)').attr('disabled', 'disabled');

Why are these two seemingly identical select menus behaving differently? I would like both to act like the static menu (keep 1st value selected) is that possible?

It should also be noted I tried wrapping the disable function in $(document).ready to rule out an issue of the menu not being rendered yet but there was no change. I also tried having two distinct classes with two separate calls to disable the options to make sure its wasn't clashing somehow with no change.

like image 980
DasBeasto Avatar asked Jul 22 '15 14:07

DasBeasto


1 Answers

Why are these two seemingly identical select menus behaving differently

This is because the first select was already part of the document and was parsed. As per the spec here:

The initial state has the first option selected..

and hence the first option was pre-selected. Later on when you disable one option, it doesn't change the selection.

Example 1: You can see that the first select has disabled attribute already applied to the first option in markup. The second option gets pre-selected, as compared to the second select.

<select class="dropMenu">
    <option value="1" disabled>First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

In your case of dynamically adding a select using Javascript, the second select was created and added to the body immediately. When this became the part of DOM, there are no options and hence no pre-selection possible. Later when you append options to it, and then disable one of the options, it seems that it gets executed too fast and by the time it is loaded the first option is already disabled and the second one gets pre-selected.

Example 2: Do NOT append the select immediately to the body. Append it after you have the options populated. This time the first option will be pre-selected despite you changing the disabled attribute later on.

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

sel.appendTo('body'); /* <--- append here */

$('.dropMenu option:nth-child(1)').prop('disabled', true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

Example 3: Add a delay before you disable an option. This will give you the intended behaviour of getting the first option pre-selected because it will have enough time.

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

setTimeout(disable, 1000); /* <--- give some delay here */

function disable() {
    $('.dropMenu option:nth-child(1)').prop('disabled', true);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>

Example 4: You can also select one option explicitly before disabling them.

var arr = [
  {val : 1, text: 'One'},
  {val : 2, text: 'Two'},
  {val : 3, text: 'Three'},
  {val : 4, text: 'Four'}
];

var sel = $('<select class="dropMenu">').appendTo('body');
$(arr).each(function () {
    sel.append($("<option>").attr('value', this.val).text(this.text));
});

$('.dropMenu option:nth-child(1)').prop('selected', true); /* <-- select explicitly */
$('.dropMenu option:nth-child(1)').prop('disabled', true);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="dropMenu">
    <option value="1">First</option>
    <option value="2">Second</option>
    <option value="3">Third</option>
    <option value="4">fourth</option>
</select>
like image 147
Abhitalks Avatar answered Oct 27 '22 01:10

Abhitalks