Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 668a33d

Browse files
committed
fix(select): allow to select first option with value undefined
Previously, the value observer incorrectly assumed a value had changed even if it was the first time it was set, which caused it to remove an option with the value `undefined` from the internal option map. Fixes #16653 Closes #16656
1 parent 19e2347 commit 668a33d

File tree

2 files changed

+39
-16
lines changed

2 files changed

+39
-16
lines changed

src/ng/directive/select.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ var SelectController =
383383

384384
if (optionAttrs.$attr.ngValue) {
385385
// The value attribute is set by ngValue
386-
var oldVal, hashedVal = NaN;
386+
var oldVal, hashedVal;
387387
optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
388388

389389
var removal;

test/ng/directive/selectSpec.js

+38-15
Original file line numberDiff line numberDiff line change
@@ -1530,11 +1530,14 @@ describe('select', function() {
15301530
['a'],
15311531
NaN
15321532
], function(prop) {
1533+
15331534
scope.option1 = prop;
1535+
scope.option2 = 'red';
15341536
scope.selected = 'NOMATCH';
15351537

15361538
compile('<select ng-model="selected">' +
15371539
'<option ng-value="option1">{{option1}}</option>' +
1540+
'<option ng-value="option2">{{option2}}</option>' +
15381541
'</select>');
15391542

15401543
scope.$digest();
@@ -1571,10 +1574,12 @@ describe('select', function() {
15711574
NaN
15721575
], function(prop) {
15731576
scope.option = prop;
1577+
scope.option2 = 'red';
15741578
scope.selected = 'NOMATCH';
15751579

15761580
compile('<select ng-model="selected">' +
15771581
'<option ng-value="option">{{option}}</option>' +
1582+
'<option ng-value="option2">{{option2}}</option>' +
15781583
'</select>');
15791584

15801585
var selectController = element.controller('select');
@@ -1604,7 +1609,7 @@ describe('select', function() {
16041609

16051610
expect(scope.selected).toBe(null);
16061611
expect(element[0].selectedIndex).toBe(0);
1607-
expect(element.find('option').length).toBe(2);
1612+
expect(element.find('option').length).toBe(3);
16081613
expect(element.find('option').eq(0).prop('selected')).toBe(true);
16091614
expect(element.find('option').eq(0).val()).toBe(unknownValue(prop));
16101615
expect(element.find('option').eq(1).prop('selected')).toBe(false);
@@ -1617,6 +1622,7 @@ describe('select', function() {
16171622
expect(element.find('option').eq(0).val()).toBe('string:UPDATEDVALUE');
16181623
});
16191624

1625+
16201626
it('should interact with custom attribute $observe and $set calls', function() {
16211627
var log = [], optionAttr;
16221628

@@ -1638,26 +1644,43 @@ describe('select', function() {
16381644
optionAttr.$set('value', 'update');
16391645
expect(log[1]).toBe('update');
16401646
expect(element.find('option').eq(1).val()).toBe('string:update');
1647+
});
1648+
16411649

1650+
it('should ignore the option text / value attribute if the ngValue attribute exists', function() {
1651+
scope.ngvalue = 'abc';
1652+
scope.value = 'def';
1653+
scope.textvalue = 'ghi';
1654+
1655+
compile('<select ng-model="x"><option ng-value="ngvalue" value="{{value}}">{{textvalue}}</option></select>');
1656+
expect(element).toEqualSelect([unknownValue(undefined)], 'string:abc');
16421657
});
16431658

1644-
it('should ignore the option text / value attribute if the ngValue attribute exists', function() {
1645-
scope.ngvalue = 'abc';
1646-
scope.value = 'def';
1647-
scope.textvalue = 'ghi';
16481659

1649-
compile('<select ng-model="x"><option ng-value="ngvalue" value="{{value}}">{{textvalue}}</option></select>');
1650-
expect(element).toEqualSelect([unknownValue(undefined)], 'string:abc');
1651-
});
1660+
it('should ignore option text with multiple interpolations if the ngValue attribute exists', function() {
1661+
scope.ngvalue = 'abc';
1662+
scope.textvalue = 'def';
1663+
scope.textvalue2 = 'ghi';
16521664

1653-
it('should ignore option text with multiple interpolations if the ngValue attribute exists', function() {
1654-
scope.ngvalue = 'abc';
1655-
scope.textvalue = 'def';
1656-
scope.textvalue2 = 'ghi';
1665+
compile('<select ng-model="x"><option ng-value="ngvalue">{{textvalue}} {{textvalue2}}</option></select>');
1666+
expect(element).toEqualSelect([unknownValue(undefined)], 'string:abc');
1667+
});
1668+
1669+
1670+
it('should select the first option if it is `undefined`', function() {
1671+
scope.selected = undefined;
1672+
1673+
scope.option1 = undefined;
1674+
scope.option2 = 'red';
1675+
1676+
compile('<select ng-model="selected">' +
1677+
'<option ng-value="option1">{{option1}}</option>' +
1678+
'<option ng-value="option2">{{option2}}</option>' +
1679+
'</select>');
1680+
1681+
expect(element).toEqualSelect(['undefined:undefined'], 'string:red');
1682+
});
16571683

1658-
compile('<select ng-model="x"><option ng-value="ngvalue">{{textvalue}} {{textvalue2}}</option></select>');
1659-
expect(element).toEqualSelect([unknownValue(undefined)], 'string:abc');
1660-
});
16611684

16621685
describe('and select[multiple]', function() {
16631686

0 commit comments

Comments
 (0)