http://jsfiddle.net/j3oh6s3a/
For some reason appending options to a select tag doesn't select the selected='selected' attribute option, instead selects the next option in the list.
Please see the above jfiddle.
<select id="category">
<option value='1'>Categroy 1</option>
<option value='2'>Categroy 2</option>
<option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
<option value='1' data-parentid='1'>Car1</option>
<option value='2' data-parentid='1'>Car2</option>
<option selected='selected' value='3' data-parentid='1'>Car3</option>
<option value='4' data-parentid='1'>Car4</option>
<option value='5' data-parentid='1'>Car5</option>
<option value='6' data-parentid='2'>Car6</option>
<option value='7' data-parentid='2'>Car7</option>
<option value='8' data-parentid='2'>Car8</option>
<option value='9' data-parentid='3'>Car9</option>
<option value='10' data-parentid='3'>Car10</option>
<option value='11' data-parentid='3'>Car11</option>
<option value='12' data-parentid='3'>Car12</option>
</select>
$(document).ready(function(){
var allsuboptions = $('#sub-category option').remove();
var selectedOptions = allsuboptions.filter(function () {
return $(this).data('parentid').toString() === $('#category').val().toString();
});
selectedOptions.appendTo('#sub-category');
});
In the above example Car3 should be selected, but Car4 is selected after appending options to the select.
This is a tricky (and interesting) question.
If you test the fiddle on different browsers you'll see that the selected value changes: Chrome (Car4), IE (Car3), Firefox (Car5). So I have made a slight change to your fiddle to "prove a theory". You can see the changes on this link: http://jsfiddle.net/j3oh6s3a/1/. I only added a log to the filter loop so I can see the selected element in each iteration:
if ($(this).is(":selected")) { console.log("Selected value = " + $(this).val()) };
Now this is what happens (or at least my theory): Once the selected element is removed from the list each browser will proceed however thinks adequate to determine the selected option. And in this case each browser will proceed in a different way:
As the selected option has been removed, Chrome will select automatically (by default) the first option
of the remaining in the list (Car4). When this option is sent to the new list, it is automatically selected as it is newer than the previous selected option. The log is: 3, 4.
Internet Explorer does nothing, and copies each element the same way they are without caring about if they are selected or not. The original selected value will be the final selected value (Car3). The log is: 3.
Firefox will proceed like Chrome, but every time that the selected element is removed from the list, the first option of the remaining ones will be selected. The log is: 3, 4, 5, 6, 7, 8, 9, 10, 11, 12; but as the last option inserted in the list is 5, it will be the selected one.
I will check later to see if I can find any information to source this, but it will have to be tomorrow as it's a bit late here.
jQuery .remove and .append internally uses .removeChild and .appendChild methods to remove/insert the child elements.
When you use removeChild and then appendChild to add the options back, the attributes are maintained, but the property of the element are not maintained. You can read more about .prop() vs .attr() here.
In summary, attributes are initial values defined in the HTML that are parsed to set as properties to the Element by the browser, however setting the attributes doesn't guarantee setting the property.
$(function() {
var categoryDD = document.getElementById('category');
var removedOptions = remove.call(categoryDD.options);
add.call(categoryDD, removedOptions);
});
function add(options) { //add all options
for (var i = 0; i < options.length; i++) {
this.appendChild(options[i]);
}
}
function remove() { //removes all options
var el, returnOpt = [];
while (this.length) {
el = this[0];
returnOpt.push(el.parentNode.removeChild(el));
}
return returnOpt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="category">
<option value='1'>Categroy 1</option>
<option value='2' selected="selected">Categroy 2</option>
<option value='3'>Categroy 3</option>
<option value='4'>Categroy 4</option>
<option value='5'>Categroy 5</option>
<option value='6'>Categroy 6</option>
</select>
On testing the above snippet, IE 10 and FF yielded me the same result which is selecting the last option from the drop down, however chrome seems to be bugged as it always selected the next option from the original selection. The results from IE 10 and FF made a little sense as to "Not maintaining the state", however Chrome behavior seems like a bug.
Above is my theory based on my test case, however I couldn't find a legit reference that states the same.
Anyways, tryout below solutions for a consistent output.
Solution 1: Remove only options that are NOT equal to parentId.
$('#sub-category option').filter(function () {
return $(this).data('parentid').toString() !== $('#category').val().toString();
}).remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<select id="category">
<option value='1'>Categroy 1</option>
<option value='2'>Categroy 2</option>
<option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
<option value='1' data-parentid='1'>Car1</option>
<option value='2' data-parentid='1'>Car2</option>
<option selected='selected' value='3' data-parentid='1'>Car3</option>
<option value='4' data-parentid='1'>Car4</option>
<option value='5' data-parentid='1'>Car5</option>
<option value='6' data-parentid='2'>Car6</option>
<option value='7' data-parentid='2'>Car7</option>
<option value='8' data-parentid='2'>Car8</option>
<option value='9' data-parentid='3'>Car9</option>
<option value='10' data-parentid='3'>Car10</option>
<option value='11' data-parentid='3'>Car11</option>
<option value='12' data-parentid='3'>Car12</option>
</select>
Solution 2: [based on your original answer] The solution is simple, just get the select value before removing the options and set the selection after using .append.
var $subcategory = $('#sub-category');
var selectedOption = $subcategory.val();
var allsuboptions = $subcategory.find('option').remove();
var selectedOptions = allsuboptions.filter(function() {
return $(this).data('parentid').toString() === $('#category').val().toString();
});
selectedOptions.appendTo('#sub-category');
$subcategory.val(selectedOption);
<select id="category">
<option value='1'>Categroy 1</option>
<option value='2'>Categroy 2</option>
<option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
<option value='1' data-parentid='1'>Car1</option>
<option value='2' data-parentid='1'>Car2</option>
<option selected='selected' value='3' data-parentid='1'>Car3</option>
<option value='4' data-parentid='1'>Car4</option>
<option value='5' data-parentid='1'>Car5</option>
<option value='6' data-parentid='2'>Car6</option>
<option value='7' data-parentid='2'>Car7</option>
<option value='8' data-parentid='2'>Car8</option>
<option value='9' data-parentid='3'>Car9</option>
<option value='10' data-parentid='3'>Car10</option>
<option value='11' data-parentid='3'>Car11</option>
<option value='12' data-parentid='3'>Car12</option>
</select>
What you're not seeing is the difference between the "selected" property and the "selected" attribute. If you put this at the end of your code you can see it:
// Attribute
console.log( $("#sub-category").find("[selected]").val() );
// Property
console.log( $("#sub-category").find(":selected").val() );
Your option with value "3" has the selected attribute, but not the property, it's the opposite for the option with value "4".
Whenever you add options inside a select, you must re-select the desired one:
$("#sub-category").find("[selected]").prop("selected", true);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With