From cf93847542d4b6cafd0a68d995a84eb02b5bb378 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Wed, 15 Jun 2016 17:10:28 +0200 Subject: [PATCH] fix(ngOptions): don't duplicate groups with falsy values This happened when the options were updated, because ngOptions would fail to remove optgroups with falsy values Related #14781 --- src/ng/directive/ngOptions.js | 5 +- test/ng/directive/ngOptionsSpec.js | 81 ++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/src/ng/directive/ngOptions.js b/src/ng/directive/ngOptions.js index a4444f70df12..fffac750dd14 100644 --- a/src/ng/directive/ngOptions.js +++ b/src/ng/directive/ngOptions.js @@ -629,7 +629,7 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, for (var i = options.items.length - 1; i >= 0; i--) { var option = options.items[i]; - if (option.group) { + if (isDefined(option.group)) { jqLiteRemove(option.element.parentNode); } else { jqLiteRemove(option.element); @@ -661,7 +661,8 @@ var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, listFragment.appendChild(groupElement); // Update the label on the group element - groupElement.label = option.group; + // "null" is special cased because of Safari + groupElement.label = option.group === null ? 'null' : option.group; // Store it for use later groupElementMap[option.group] = groupElement; diff --git a/test/ng/directive/ngOptionsSpec.js b/test/ng/directive/ngOptionsSpec.js index b830073b1450..8fb6a2a9fa3f 100644 --- a/test/ng/directive/ngOptionsSpec.js +++ b/test/ng/directive/ngOptionsSpec.js @@ -1789,6 +1789,87 @@ describe('ngOptions', function() { }); + it('should group if the group has a falsy value (except undefined)', function() { + createSelect({ + 'ng-model': 'selected', + 'ng-options': 'item.name group by item.group for item in values' + }); + + scope.$apply(function() { + scope.values = [{name: 'A'}, + {name: 'B', group: ''}, + {name: 'C', group: null}, + {name: 'D', group: false}, + {name: 'E', group: 0}]; + scope.selected = scope.values[0]; + }); + + var optgroups = element.find('optgroup'); + var options = element.find('option'); + + expect(optgroups.length).toEqual(4); + expect(options.length).toEqual(5); + + expect(optgroups[0].label).toBe(''); + expect(optgroups[1].label).toBe('null'); + expect(optgroups[2].label).toBe('false'); + expect(optgroups[3].label).toBe('0'); + + expect(options[0].textContent).toBe('A'); + expect(options[0].parentNode).toBe(element[0]); + + expect(options[1].textContent).toBe('B'); + expect(options[1].parentNode).toBe(optgroups[0]); + + expect(options[2].textContent).toBe('C'); + expect(options[2].parentNode).toBe(optgroups[1]); + + expect(options[3].textContent).toBe('D'); + expect(options[3].parentNode).toBe(optgroups[2]); + + expect(options[4].textContent).toBe('E'); + expect(options[4].parentNode).toBe(optgroups[3]); + }); + + + it('should not duplicate a group with a falsy value when the options are updated', function() { + + scope.$apply(function() { + scope.values = [{value: 'A', group: ''}, + {value: 'B', group: 'First'}]; + scope.selected = scope.values[0]; + }); + + createSelect({ + 'ng-model': 'selected', + 'ng-options': 'item.value group by item.group for item in values' + }); + + scope.$apply(function() { + scope.values.push({value: 'C', group: false}); + }); + + var optgroups = element.find('optgroup'); + var options = element.find('option'); + + expect(optgroups.length).toEqual(3); + expect(options.length).toEqual(3); + + expect(optgroups[0].label).toBe(''); + expect(optgroups[1].label).toBe('First'); + expect(optgroups[2].label).toBe('false'); + + expect(options[0].textContent).toBe('A'); + expect(options[0].parentNode).toBe(optgroups[0]); + + expect(options[1].textContent).toBe('B'); + expect(options[1].parentNode).toBe(optgroups[1]); + + expect(options[2].textContent).toBe('C'); + expect(options[2].parentNode).toBe(optgroups[2]); + }); + + it('should bind to scope value and track/identify objects', function() { createSelect({ 'ng-model': 'selected',