Skip to content

Commit d04cc68

Browse files
committed
fix(ngOptions): select disabled option when set from model
When a disabled option is set as the ngModel, ngOptions will now select the option in the select element, which will set select.val() to the option hash value and visually show the option value / label as selected in the select box. Previously, disabled options forced the unknown value. The previous behavior is inconsistent with both default HTML behavior and select with ngModel but without ngOptions. Both allow disabled values to be selected programmatically. Common use cases for this behavior include options that where previously valid, but have been disabled, and cannot be selected again. This commit removes a duplicate tests, all other tests that previously checked that disabled options are not set have been adjusted to the ensure the opposite. Fixes angular#12756
1 parent 7ecfa5d commit d04cc68

File tree

2 files changed

+21
-46
lines changed

2 files changed

+21
-46
lines changed

src/ng/directive/ngOptions.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
467467
selectCtrl.writeValue = function writeNgOptionsValue(value) {
468468
var option = options.getOptionFromViewValue(value);
469469

470-
if (option && !option.disabled) {
470+
if (option) {
471471
// Don't update the option when it is already selected.
472472
// For example, the browser will select the first option by default. In that case,
473473
// most properties are set automatically - except the `selected` attribute, which we
@@ -529,7 +529,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
529529
if (value) {
530530
value.forEach(function(item) {
531531
var option = options.getOptionFromViewValue(item);
532-
if (option && !option.disabled) option.element.selected = true;
532+
if (option) option.element.selected = true;
533533
});
534534
}
535535
};

test/ng/directive/ngOptionsSpec.js

+19-44
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ describe('ngOptions', function() {
751751
});
752752

753753

754-
it('should not select disabled options when model changes', function() {
754+
it('should select disabled options when model changes', function() {
755755
scope.options = [
756756
{ name: 'white', value: '#FFFFFF' },
757757
{ name: 'one', value: 1, unavailable: true },
@@ -772,11 +772,14 @@ describe('ngOptions', function() {
772772
scope.$apply('selected = 1');
773773
options = element.find('option');
774774

775-
expect(element.val()).toEqualUnknownValue('?');
776-
expect(options.length).toEqual(5);
777-
expect(options.eq(0).prop('selected')).toEqual(true);
775+
// jQuery returns null for val() when the option is disabled, see
776+
// https://bugs.jquery.com/ticket/13097
777+
expect(element[0].value).toBe('number:1');
778+
expect(options.length).toEqual(4);
779+
expect(options.eq(0).prop('selected')).toEqual(false);
780+
expect(options.eq(1).prop('selected')).toEqual(true);
778781
expect(options.eq(2).prop('selected')).toEqual(false);
779-
expect(options.eq(4).prop('selected')).toEqual(false);
782+
expect(options.eq(3).prop('selected')).toEqual(false);
780783
});
781784

782785

@@ -796,11 +799,14 @@ describe('ngOptions', function() {
796799
scope.$apply('selected = 1');
797800
var options = element.find('option');
798801

799-
expect(element.val()).toEqualUnknownValue('?');
800-
expect(options.length).toEqual(5);
801-
expect(options.eq(0).prop('selected')).toEqual(true);
802+
// jQuery returns null for val() when the option is disabled, see
803+
// https://bugs.jquery.com/ticket/13097
804+
expect(element[0].value).toBe('number:1');
805+
expect(options.length).toEqual(4);
806+
expect(options.eq(0).prop('selected')).toEqual(false);
807+
expect(options.eq(1).prop('selected')).toEqual(true);
802808
expect(options.eq(2).prop('selected')).toEqual(false);
803-
expect(options.eq(4).prop('selected')).toEqual(false);
809+
expect(options.eq(3).prop('selected')).toEqual(false);
804810

805811
// Now enable that option
806812
scope.$apply(function() {
@@ -841,7 +847,7 @@ describe('ngOptions', function() {
841847
});
842848

843849

844-
it('should not select disabled options when model changes', function() {
850+
it('should select disabled options when model changes', function() {
845851
scope.options = [
846852
{ name: 'a', value: 0 },
847853
{ name: 'b', value: 1, unavailable: true },
@@ -866,14 +872,14 @@ describe('ngOptions', function() {
866872
scope.$apply('selected = [1,3]');
867873
options = element.find('option');
868874
expect(options.eq(0).prop('selected')).toEqual(false);
869-
expect(options.eq(1).prop('selected')).toEqual(false);
875+
expect(options.eq(1).prop('selected')).toEqual(true);
870876
expect(options.eq(2).prop('selected')).toEqual(false);
871877
expect(options.eq(3).prop('selected')).toEqual(true);
872878

873879
// Now only select the disabled option
874880
scope.$apply('selected = [1]');
875881
expect(options.eq(0).prop('selected')).toEqual(false);
876-
expect(options.eq(1).prop('selected')).toEqual(false);
882+
expect(options.eq(1).prop('selected')).toEqual(true);
877883
expect(options.eq(2).prop('selected')).toEqual(false);
878884
expect(options.eq(3).prop('selected')).toEqual(false);
879885
});
@@ -897,7 +903,7 @@ describe('ngOptions', function() {
897903
var options = element.find('option');
898904

899905
expect(options.eq(0).prop('selected')).toEqual(false);
900-
expect(options.eq(1).prop('selected')).toEqual(false);
906+
expect(options.eq(1).prop('selected')).toEqual(true);
901907
expect(options.eq(2).prop('selected')).toEqual(false);
902908
expect(options.eq(3).prop('selected')).toEqual(false);
903909

@@ -2515,37 +2521,6 @@ describe('ngOptions', function() {
25152521
expect(element.find('option')[1].selected).toBeTruthy();
25162522
});
25172523

2518-
it('should not write disabled selections from model', function() {
2519-
scope.selected = [30];
2520-
scope.options = [
2521-
{ name: 'white', value: '#FFFFFF' },
2522-
{ name: 'one', value: 1, unavailable: true },
2523-
{ name: 'notTrue', value: false },
2524-
{ name: 'thirty', value: 30, unavailable: false }
2525-
];
2526-
createSelect({
2527-
'ng-options': 'o.value as o.name disable when o.unavailable for o in options',
2528-
'ng-model': 'selected',
2529-
'multiple': true
2530-
});
2531-
2532-
var options = element.find('option');
2533-
2534-
expect(options.eq(0).prop('selected')).toEqual(false);
2535-
expect(options.eq(1).prop('selected')).toEqual(false);
2536-
expect(options.eq(2).prop('selected')).toEqual(false);
2537-
expect(options.eq(3).prop('selected')).toEqual(true);
2538-
2539-
scope.$apply(function() {
2540-
scope.selected.push(1);
2541-
});
2542-
2543-
expect(options.eq(0).prop('selected')).toEqual(false);
2544-
expect(options.eq(1).prop('selected')).toEqual(false);
2545-
expect(options.eq(2).prop('selected')).toEqual(false);
2546-
expect(options.eq(3).prop('selected')).toEqual(true);
2547-
});
2548-
25492524

25502525
it('should update model on change', function() {
25512526
createMultiSelect();

0 commit comments

Comments
 (0)