diff --git a/spec/defaultBindings/optionsBehaviors.js b/spec/defaultBindings/optionsBehaviors.js index d768e3a66..fbc1ee99b 100644 --- a/spec/defaultBindings/optionsBehaviors.js +++ b/spec/defaultBindings/optionsBehaviors.js @@ -96,6 +96,34 @@ describe('Binding: Options', function() { expect(testNode.childNodes[0]).toHaveSelectedValues(["B"]); }); + it('Should select first option when removing the selected option and the original first option', function () { + // This test failed in IE<=8 without changes made in #1208 + testNode.innerHTML = ''; + var viewModel = { + filterValues: ko.observableArray() + }; + ko.applyBindings(viewModel, testNode); + expect(testNode.childNodes[0]).toHaveSelectedValues([undefined]); + + viewModel.filterValues.push("1"); + viewModel.filterValues.push("2"); + expect(testNode.childNodes[0]).toHaveSelectedValues([undefined]); + }); + it('Should trigger a change event when the options selection is populated or changed by modifying the options data (single select)', function() { var observable = new ko.observableArray(["A", "B", "C"]), changeHandlerFireCount = 0; testNode.innerHTML = ""; diff --git a/src/binding/defaultBindings/options.js b/src/binding/defaultBindings/options.js index b5513bfa4..4d520cdb1 100755 --- a/src/binding/defaultBindings/options.js +++ b/src/binding/defaultBindings/options.js @@ -21,8 +21,10 @@ ko.bindingHandlers['options'] = { var unwrappedArray = ko.utils.unwrapObservable(valueAccessor()); var includeDestroyed = allBindings.get('optionsIncludeDestroyed'); + var arrayToDomNodeChildrenOptions = {}; var captionPlaceholder = {}; var captionValue; + var previousSelectedValues; if (element.multiple) { previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue); @@ -88,6 +90,15 @@ ko.bindingHandlers['options'] = { return [option]; } + // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection + // problem in IE<=8. See https://github.com/knockout/knockout/issues/1208 + if (ko.utils.ieVersion <= 8) { + arrayToDomNodeChildrenOptions['beforeRemove'] = + function (option) { + element.removeChild(option); + }; + } + function setSelectionCallback(arrayEntry, newOptions) { // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document. // That's why we first added them without selection. Now it's time to set the selection. @@ -109,7 +120,7 @@ ko.bindingHandlers['options'] = { } } - ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, null, callback); + ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback); // Determine if the selection has changed as a result of updating the options list var selectionChanged;