From 42152eb366cbdef89d397288b01e4d19a3e915ab Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 24 Aug 2021 07:10:52 +0200 Subject: [PATCH] fix(material/select): error if selected value is accessed too early Fixes that the select throws if the `selected` value is accessed before everything is initialized. Fixes #23371. --- .../mdc-select/select.spec.ts | 33 ++++++++++++++++--- src/material/select/select.spec.ts | 33 ++++++++++++++++--- src/material/select/select.ts | 3 +- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/material-experimental/mdc-select/select.spec.ts b/src/material-experimental/mdc-select/select.spec.ts index 9d4647314e32..4ef828f9461b 100644 --- a/src/material-experimental/mdc-select/select.spec.ts +++ b/src/material-experimental/mdc-select/select.spec.ts @@ -2709,11 +2709,34 @@ expect(panel.scrollTop) describe(`when the select's value is accessed on initialization`, () => { beforeEach(waitForAsync(() => configureMatSelectTestingModule([SelectEarlyAccessSibling]))); - it('should not throw when trying to access the selected value on init', fakeAsync(() => { - expect(() => { - TestBed.createComponent(SelectEarlyAccessSibling).detectChanges(); - }).not.toThrow(); - })); + it('should not throw when trying to access the selected value on init in the view', + fakeAsync(() => { + expect(() => { + TestBed.createComponent(SelectEarlyAccessSibling).detectChanges(); + }).not.toThrow(); + })); + + it('should not throw when reading selected value programmatically in single selection mode', + fakeAsync(() => { + expect(() => { + const fixture = TestBed.createComponent(SelectEarlyAccessSibling); + const select = fixture.debugElement.query(By.directive(MatSelect)).componentInstance; + // We're checking that accessing the getter won't throw. + select.multiple = false; + return select.selected; + }).not.toThrow(); + })); + + it('should not throw when reading selected value programmatically in multi selection mode', + fakeAsync(() => { + expect(() => { + const fixture = TestBed.createComponent(SelectEarlyAccessSibling); + const select = fixture.debugElement.query(By.directive(MatSelect)).componentInstance; + // We're checking that accessing the getter won't throw. + select.multiple = true; + return select.selected; + }).not.toThrow(); + })); }); describe('with ngIf and mat-label', () => { diff --git a/src/material/select/select.spec.ts b/src/material/select/select.spec.ts index bf450a17184e..e9a15d5fcd5f 100644 --- a/src/material/select/select.spec.ts +++ b/src/material/select/select.spec.ts @@ -2776,11 +2776,34 @@ describe('MatSelect', () => { describe(`when the select's value is accessed on initialization`, () => { beforeEach(waitForAsync(() => configureMatSelectTestingModule([SelectEarlyAccessSibling]))); - it('should not throw when trying to access the selected value on init', fakeAsync(() => { - expect(() => { - TestBed.createComponent(SelectEarlyAccessSibling).detectChanges(); - }).not.toThrow(); - })); + it('should not throw when trying to access the selected value on init in the view', + fakeAsync(() => { + expect(() => { + TestBed.createComponent(SelectEarlyAccessSibling).detectChanges(); + }).not.toThrow(); + })); + + it('should not throw when reading selected value programmatically in single selection mode', + fakeAsync(() => { + expect(() => { + const fixture = TestBed.createComponent(SelectEarlyAccessSibling); + const select = fixture.debugElement.query(By.directive(MatSelect)).componentInstance; + // We're checking that accessing the getter won't throw. + select.multiple = false; + return select.selected; + }).not.toThrow(); + })); + + it('should not throw when reading selected value programmatically in multi selection mode', + fakeAsync(() => { + expect(() => { + const fixture = TestBed.createComponent(SelectEarlyAccessSibling); + const select = fixture.debugElement.query(By.directive(MatSelect)).componentInstance; + // We're checking that accessing the getter won't throw. + select.multiple = true; + return select.selected; + }).not.toThrow(); + })); }); describe('with ngIf and mat-label', () => { diff --git a/src/material/select/select.ts b/src/material/select/select.ts index ecd4a4db7916..7f9a774e9372 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -624,7 +624,8 @@ export abstract class _MatSelectBase extends _MatSelectMixinBase implements A /** The currently selected option. */ get selected(): MatOption | MatOption[] { - return this.multiple ? this._selectionModel.selected : this._selectionModel.selected[0]; + return this.multiple ? (this._selectionModel?.selected || []) : + this._selectionModel?.selected[0]; } /** The value displayed in the trigger. */