Skip to content

Commit e04b7ae

Browse files
committed
fix(material/select): value set through property not being propagated to value accessor (#10246)
Fixes values set through the `value` property not being propagated to the `value` in the `ControlValueAccessor`. Fixes #10214. (cherry picked from commit 5f4148f)
1 parent 51ddecb commit e04b7ae

File tree

3 files changed

+43
-10
lines changed

3 files changed

+43
-10
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2155,6 +2155,17 @@ describe('MDC-based MatSelect', () => {
21552155
.withContext(`Expected label to have an asterisk, as control was required.`)
21562156
.toBeTruthy();
21572157
}));
2158+
2159+
it('should propagate the value set through the `value` property to the form field', fakeAsync(() => {
2160+
const control = fixture.componentInstance.control;
2161+
2162+
expect(control.value).toBeFalsy();
2163+
2164+
fixture.componentInstance.select.value = 'pizza-1';
2165+
fixture.detectChanges();
2166+
2167+
expect(control.value).toBe('pizza-1');
2168+
}));
21582169
});
21592170

21602171
describe('disabled behavior', () => {

src/material/select/select.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,6 +2170,17 @@ describe('MatSelect', () => {
21702170
.not.withContext(`Expected label to have an asterisk, as control was required.`)
21712171
.toBeNull();
21722172
}));
2173+
2174+
it('should propagate the value set through the `value` property to the form field', fakeAsync(() => {
2175+
const control = fixture.componentInstance.control;
2176+
2177+
expect(control.value).toBeFalsy();
2178+
2179+
fixture.componentInstance.select.value = 'pizza-1';
2180+
fixture.detectChanges();
2181+
2182+
expect(control.value).toBe('pizza-1');
2183+
}));
21732184
});
21742185

21752186
describe('disabled behavior', () => {

src/material/select/select.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,10 @@ export abstract class _MatSelectBase<C>
411411
return this._value;
412412
}
413413
set value(newValue: any) {
414-
// Always re-assign an array, because it might have been mutated.
415-
if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {
416-
if (this.options) {
417-
this._setSelectionByValue(newValue);
418-
}
414+
const hasAssigned = this._assignValue(newValue);
419415

420-
this._value = newValue;
416+
if (hasAssigned) {
417+
this._onChange(newValue);
421418
}
422419
}
423420
private _value: any;
@@ -649,7 +646,7 @@ export abstract class _MatSelectBase<C>
649646
* @param value New value to be written to the model.
650647
*/
651648
writeValue(value: any): void {
652-
this.value = value;
649+
this._assignValue(value);
653650
}
654651

655652
/**
@@ -874,10 +871,10 @@ export abstract class _MatSelectBase<C>
874871
throw getMatSelectNonArrayValueError();
875872
}
876873

877-
value.forEach((currentValue: any) => this._selectValue(currentValue));
874+
value.forEach((currentValue: any) => this._selectOptionByValue(currentValue));
878875
this._sortValues();
879876
} else {
880-
const correspondingOption = this._selectValue(value);
877+
const correspondingOption = this._selectOptionByValue(value);
881878

882879
// Shift focus to the active item. Note that we shouldn't do this in multiple
883880
// mode, because we don't know what option the user interacted with last.
@@ -897,7 +894,7 @@ export abstract class _MatSelectBase<C>
897894
* Finds and selects and option based on its value.
898895
* @returns Option that has the corresponding value.
899896
*/
900-
private _selectValue(value: any): MatOption | undefined {
897+
private _selectOptionByValue(value: any): MatOption | undefined {
901898
const correspondingOption = this.options.find((option: MatOption) => {
902899
// Skip options that are already in the model. This allows us to handle cases
903900
// where the same primitive value is selected multiple times.
@@ -924,6 +921,20 @@ export abstract class _MatSelectBase<C>
924921
return correspondingOption;
925922
}
926923

924+
/** Assigns a specific value to the select. Returns whether the value has changed. */
925+
private _assignValue(newValue: any | any[]): boolean {
926+
// Always re-assign an array, because it might have been mutated.
927+
if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {
928+
if (this.options) {
929+
this._setSelectionByValue(newValue);
930+
}
931+
932+
this._value = newValue;
933+
return true;
934+
}
935+
return false;
936+
}
937+
927938
/** Sets up a key manager to listen to keyboard events on the overlay panel. */
928939
private _initKeyManager() {
929940
this._keyManager = new ActiveDescendantKeyManager<MatOption>(this.options)

0 commit comments

Comments
 (0)