From d55aa0c7a05891ad20f3f2c75673450d70c35b39 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 10 Oct 2017 00:48:38 +0200 Subject: [PATCH] fix(select): unable to preselect array value in single selection mode (#7603) Fixes not being able to preselect an array if a select is in single selection mode due to an assumption that an array value means that we're in mutliple selection mode. Fixes #7584. --- src/lib/select/select.spec.ts | 39 +++++++++++++++++++++++++++++++++++ src/lib/select/select.ts | 21 +++++++++---------- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index aa63c39c2e76..cc53f2eeb005 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -105,6 +105,7 @@ describe('MatSelect', () => { SelectInsideFormGroup, NgModelCompareWithSelect, CustomErrorBehaviorSelect, + SingleSelectWithPreselectedArrayValues, ], providers: [ {provide: OverlayContainer, useFactory: () => { @@ -1010,6 +1011,19 @@ describe('MatSelect', () => { }); }); })); + + it('should be able to preselect an array value in single-selection mode', fakeAsync(() => { + const fixture = TestBed.createComponent(SingleSelectWithPreselectedArrayValues); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + const trigger = fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement; + + expect(trigger.textContent).toContain('Pizza'); + expect(fixture.componentInstance.options.toArray()[1].selected).toBe(true); + })); + }); describe('misc forms', () => { @@ -3872,3 +3886,28 @@ class CustomErrorBehaviorSelect { ]; errorStateMatcher: ErrorStateMatcher; } + + +@Component({ + template: ` + + + {{ food.viewValue }} + + + + ` +}) +class SingleSelectWithPreselectedArrayValues { + foods: any[] = [ + { value: ['steak-0', 'steak-1'], viewValue: 'Steak' }, + { value: ['pizza-1', 'pizza-2'], viewValue: 'Pizza' }, + { value: ['tacos-2', 'tacos-3'], viewValue: 'Tacos' }, + ]; + + selectedFoods = this.foods[1].value; + + @ViewChild(MatSelect) select: MatSelect; + @ViewChildren(MatOption) options: QueryList; +} diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index 8dfbe825b4d9..210c386ac319 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -700,18 +700,17 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, * found with the designated value, the select trigger is cleared. */ private _setSelectionByValue(value: any | any[], isUserInput = false): void { - const isArray = Array.isArray(value); - - if (this.multiple && value && !isArray) { - throw getMatSelectNonArrayValueError(); - } - - this._clearSelection(); + if (this.multiple && value) { + if (!Array.isArray(value)) { + throw getMatSelectNonArrayValueError(); + } - if (isArray) { + this._clearSelection(); value.forEach((currentValue: any) => this._selectValue(currentValue, isUserInput)); this._sortValues(); } else { + this._clearSelection(); + const correspondingOption = this._selectValue(value, isUserInput); // Shift focus to the active item. Note that we shouldn't do this in multiple @@ -844,10 +843,10 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, private _propagateChanges(fallbackValue?: any): void { let valueToEmit: any = null; - if (Array.isArray(this.selected)) { - valueToEmit = this.selected.map(option => option.value); + if (this.multiple) { + valueToEmit = (this.selected as MatOption[]).map(option => option.value); } else { - valueToEmit = this.selected ? this.selected.value : fallbackValue; + valueToEmit = this.selected ? (this.selected as MatOption).value : fallbackValue; } this._value = valueToEmit;