diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index e44b61e955cb..06ce30c4dc37 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -322,7 +322,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { // We try to reuse these if possible // - optionGroupsCache[0] is the options with no option group // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element - optionGroupsCache = [[{element: selectElement, label:''}]]; + optionGroupsCache = [[{element: selectElement, label:''}]], + changeEventFired = false; if (nullOption) { // compile the element since there might be bindings in it @@ -341,6 +342,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { selectElement.empty(); selectElement.on('change', function() { + changeEventFired = true; scope.$apply(function() { var optionGroup, collection = valuesFn(scope) || [], @@ -409,8 +411,8 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { optionGroupName, optionGroup, option, - existingParent, existingOptions, existingOption, modelValue = ctrl.$modelValue, + existingParent, existingOptions, existingOption, values = valuesFn(scope) || [], keys = keyName ? sortedKeys(values) : values, key, @@ -529,7 +531,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { lastElement.val(existingOption.id = option.id); } // lastElement.prop('selected') provided by jQuery has side-effects - if (lastElement[0].selected !== option.selected) { + // FF will update selected property on DOM elements when hovering, + // so we shouldn't check those unless a change event has happened + if ((changeEventFired && lastElement[0].selected !== option.selected) || + existingOption.selected !== option.selected) { lastElement.prop('selected', (existingOption.selected = option.selected)); } } else { @@ -573,6 +578,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { while(optionGroupsCache.length > groupIndex) { optionGroupsCache.pop()[0].element.remove(); } + changeEventFired = false; } } } diff --git a/test/ng/directive/selectSpec.js b/test/ng/directive/selectSpec.js index 6fcd1fe05f82..d2215506d2f1 100644 --- a/test/ng/directive/selectSpec.js +++ b/test/ng/directive/selectSpec.js @@ -733,6 +733,21 @@ describe('select', function() { expect(sortedHtml(options[2])).toEqual(''); }); + it('should ignore option object selected changes', function() { + createSingleSelect(); + + scope.$apply(function() { + scope.values = [{name: 'A'}, {name: 'B'}, {name: 'C'}]; + scope.selected = scope.values[0]; + }); + + var options = element.find('option'); + var optionToSelect = options.eq(1); + optionToSelect.prop('selected', true); + scope.$digest(); + expect(optionToSelect.prop('selected')).toBe(true); + }); + describe('binding', function() { it('should bind to scope value', function() {