Skip to content

Commit

Permalink
fix(material/select): value set through property not being propagated…
Browse files Browse the repository at this point in the history
… 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)
  • Loading branch information
crisbeto committed Mar 22, 2022
1 parent 51ddecb commit e04b7ae
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 10 deletions.
11 changes: 11 additions & 0 deletions src/material-experimental/mdc-select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,17 @@ describe('MDC-based MatSelect', () => {
.withContext(`Expected label to have an asterisk, as control was required.`)
.toBeTruthy();
}));

it('should propagate the value set through the `value` property to the form field', fakeAsync(() => {
const control = fixture.componentInstance.control;

expect(control.value).toBeFalsy();

fixture.componentInstance.select.value = 'pizza-1';
fixture.detectChanges();

expect(control.value).toBe('pizza-1');
}));
});

describe('disabled behavior', () => {
Expand Down
11 changes: 11 additions & 0 deletions src/material/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2170,6 +2170,17 @@ describe('MatSelect', () => {
.not.withContext(`Expected label to have an asterisk, as control was required.`)
.toBeNull();
}));

it('should propagate the value set through the `value` property to the form field', fakeAsync(() => {
const control = fixture.componentInstance.control;

expect(control.value).toBeFalsy();

fixture.componentInstance.select.value = 'pizza-1';
fixture.detectChanges();

expect(control.value).toBe('pizza-1');
}));
});

describe('disabled behavior', () => {
Expand Down
31 changes: 21 additions & 10 deletions src/material/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,13 +411,10 @@ export abstract class _MatSelectBase<C>
return this._value;
}
set value(newValue: any) {
// Always re-assign an array, because it might have been mutated.
if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {
if (this.options) {
this._setSelectionByValue(newValue);
}
const hasAssigned = this._assignValue(newValue);

this._value = newValue;
if (hasAssigned) {
this._onChange(newValue);
}
}
private _value: any;
Expand Down Expand Up @@ -649,7 +646,7 @@ export abstract class _MatSelectBase<C>
* @param value New value to be written to the model.
*/
writeValue(value: any): void {
this.value = value;
this._assignValue(value);
}

/**
Expand Down Expand Up @@ -874,10 +871,10 @@ export abstract class _MatSelectBase<C>
throw getMatSelectNonArrayValueError();
}

value.forEach((currentValue: any) => this._selectValue(currentValue));
value.forEach((currentValue: any) => this._selectOptionByValue(currentValue));
this._sortValues();
} else {
const correspondingOption = this._selectValue(value);
const correspondingOption = this._selectOptionByValue(value);

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

/** Assigns a specific value to the select. Returns whether the value has changed. */
private _assignValue(newValue: any | any[]): boolean {
// Always re-assign an array, because it might have been mutated.
if (newValue !== this._value || (this._multiple && Array.isArray(newValue))) {
if (this.options) {
this._setSelectionByValue(newValue);
}

this._value = newValue;
return true;
}
return false;
}

/** Sets up a key manager to listen to keyboard events on the overlay panel. */
private _initKeyManager() {
this._keyManager = new ActiveDescendantKeyManager<MatOption>(this.options)
Expand Down

0 comments on commit e04b7ae

Please sign in to comment.