From 70dbde1830c0cef2e684c287c377c8581a40cf20 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 25 Mar 2017 16:11:41 +0100 Subject: [PATCH] fix(select): exception if selected value is accessed on init Fixes an error that is thrown if something attempts to access the `selected` value of `md-select` too early. The issue comes from the fact that the underlying `SelectionModel` gets initialized too late in `ngAfterContentInit`. Fixes #3750. --- src/lib/select/select.spec.ts | 18 +++++++++++++++++- src/lib/select/select.ts | 8 ++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts index df1fb46f739a..fac161e64a8e 100644 --- a/src/lib/select/select.spec.ts +++ b/src/lib/select/select.spec.ts @@ -46,7 +46,8 @@ describe('MdSelect', () => { ThrowsErrorOnInit, BasicSelectOnPush, BasicSelectOnPushPreselected, - SelectWithPlainTabindex + SelectWithPlainTabindex, + SelectEarlyAccessSibling ], providers: [ {provide: OverlayContainer, useFactory: () => { @@ -1322,6 +1323,12 @@ describe('MdSelect', () => { }).toThrowError(new RegExp('Oh no!', 'g')); })); + it('should not throw when trying to access the selected value on init', async(() => { + expect(() => { + TestBed.createComponent(SelectEarlyAccessSibling).detectChanges(); + }).not.toThrow(); + })); + }); describe('change event', () => { @@ -1896,6 +1903,15 @@ class MultiSelect { }) class SelectWithPlainTabindex { } +@Component({ + selector: 'select-early-sibling-access', + template: ` + +
+ ` +}) +class SelectEarlyAccessSibling { } + class FakeViewportRuler { getViewportRect() { diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts index c220082e5db2..96b9053fdc25 100644 --- a/src/lib/select/select.ts +++ b/src/lib/select/select.ts @@ -15,6 +15,7 @@ import { ViewChild, ChangeDetectorRef, Attribute, + OnInit, } from '@angular/core'; import {MdOption, MdOptionSelectionChange} from '../core/option/option'; import {ENTER, SPACE} from '../core/keyboard/keycodes'; @@ -118,7 +119,7 @@ export type MdSelectFloatPlaceholderType = 'always' | 'never' | 'auto'; ], exportAs: 'mdSelect', }) -export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestroy { +export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlValueAccessor { /** Whether or not the overlay panel is open. */ private _panelOpen = false; @@ -304,8 +305,11 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr this._tabIndex = parseInt(tabIndex) || 0; } - ngAfterContentInit() { + ngOnInit() { this._selectionModel = new SelectionModel(this.multiple, null, false); + } + + ngAfterContentInit() { this._initKeyManager(); this._changeSubscription = this.options.changes.startWith(null).subscribe(() => {