Skip to content

Commit c4078aa

Browse files
authored
fix(material/select): option active styling not removed when value is changed programmatically (#20649)
If an option is selected by the user and the value is changed programmatically afterwards, we weren't removing the active state from the previous option. This seems to be a regression from #19970. These changes resolve the issue and preserve the fix from #19970 by resetting the active styling manually.
1 parent 7beb952 commit c4078aa

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

src/material-experimental/mdc-select/select.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,39 @@ describe('MDC-based MatSelect', () => {
10981098
expect(options[1].getAttribute('aria-disabled')).toEqual('false');
10991099
expect(options[2].getAttribute('aria-disabled')).toEqual('false');
11001100
}));
1101+
1102+
it('should remove the active state from options that have been deselected while closed',
1103+
fakeAsync(() => {
1104+
let activeOptions = options.filter(option => {
1105+
return option.classList.contains('mat-mdc-option-active');
1106+
});
1107+
expect(activeOptions).toEqual([options[0]],
1108+
'Expected first option to have active styles.');
1109+
1110+
options[1].click();
1111+
fixture.detectChanges();
1112+
trigger.click();
1113+
fixture.detectChanges();
1114+
flush();
1115+
1116+
activeOptions = options.filter(option => {
1117+
return option.classList.contains('mat-mdc-option-active');
1118+
});
1119+
expect(activeOptions).toEqual([options[1]],
1120+
'Expected only selected option to be marked as active after it is clicked.');
1121+
1122+
fixture.componentInstance.control.setValue(fixture.componentInstance.foods[7].value);
1123+
fixture.detectChanges();
1124+
trigger.click();
1125+
fixture.detectChanges();
1126+
flush();
1127+
1128+
activeOptions = options.filter(option => {
1129+
return option.classList.contains('mat-mdc-option-active');
1130+
});
1131+
expect(activeOptions).toEqual([options[7]],
1132+
'Expected only selected option to be marked as active after the value has changed.');
1133+
}));
11011134
});
11021135

11031136
describe('for option groups', () => {

src/material/select/select.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,33 @@ describe('MatSelect', () => {
10661066
expect(options[1].getAttribute('aria-disabled')).toEqual('false');
10671067
expect(options[2].getAttribute('aria-disabled')).toEqual('false');
10681068
}));
1069+
1070+
it('should remove the active state from options that have been deselected while closed',
1071+
fakeAsync(() => {
1072+
let activeOptions = options.filter(option => option.classList.contains('mat-active'));
1073+
expect(activeOptions).toEqual([options[0]],
1074+
'Expected first option to have active styles.');
1075+
1076+
options[1].click();
1077+
fixture.detectChanges();
1078+
trigger.click();
1079+
fixture.detectChanges();
1080+
flush();
1081+
1082+
activeOptions = options.filter(option => option.classList.contains('mat-active'));
1083+
expect(activeOptions).toEqual([options[1]],
1084+
'Expected only selected option to be marked as active after it is clicked.');
1085+
1086+
fixture.componentInstance.control.setValue(fixture.componentInstance.foods[7].value);
1087+
fixture.detectChanges();
1088+
trigger.click();
1089+
fixture.detectChanges();
1090+
flush();
1091+
1092+
activeOptions = options.filter(option => option.classList.contains('mat-active'));
1093+
expect(activeOptions).toEqual([options[7]],
1094+
'Expected only selected option to be marked as active after the value has changed.');
1095+
}));
10691096
});
10701097

10711098
describe('for option groups', () => {

src/material/select/select.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -813,16 +813,17 @@ export abstract class _MatSelectBase<C> extends _MatSelectMixinBase implements A
813813
* found with the designated value, the select trigger is cleared.
814814
*/
815815
private _setSelectionByValue(value: any | any[]): void {
816+
this._selectionModel.selected.forEach(option => option.setInactiveStyles());
817+
this._selectionModel.clear();
818+
816819
if (this.multiple && value) {
817820
if (!Array.isArray(value) && (typeof ngDevMode === 'undefined' || ngDevMode)) {
818821
throw getMatSelectNonArrayValueError();
819822
}
820823

821-
this._selectionModel.clear();
822824
value.forEach((currentValue: any) => this._selectValue(currentValue));
823825
this._sortValues();
824826
} else {
825-
this._selectionModel.clear();
826827
const correspondingOption = this._selectValue(value);
827828

828829
// Shift focus to the active item. Note that we shouldn't do this in multiple

0 commit comments

Comments
 (0)