From 7398bb317f249015e6a91ad8dc84aba9858a40ce Mon Sep 17 00:00:00 2001 From: crisbeto Date: Mon, 22 Jul 2019 22:01:12 +0200 Subject: [PATCH] fix(button-toggle): error when check value is set via static attribute in Ivy Fixes the button toggle throwing an error under Ivy, if its `checked` value is set via a static attribute (e.g. ``). The issue comes from the fact that in Ivy static inputs are set during creation, which means that the selection model isn't initialized yet. Fixes #16471. --- src/material/button-toggle/button-toggle.spec.ts | 14 ++++++++++++++ src/material/button-toggle/button-toggle.ts | 14 +++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/material/button-toggle/button-toggle.spec.ts b/src/material/button-toggle/button-toggle.spec.ts index 90c366dd1169..22cbc3e3a4f9 100644 --- a/src/material/button-toggle/button-toggle.spec.ts +++ b/src/material/button-toggle/button-toggle.spec.ts @@ -845,6 +845,20 @@ describe('MatButtonToggle without forms', () => { expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(false); expect(fixture.componentInstance.toggles.toArray()[2].checked).toBe(true); }); + + it('should not throw if initial value is set during creation', () => { + const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroupMultiple); + + // In Ivy static inputs are set during creation. We simulate this by not calling + // `fixture.detectChanges` immediately, but getting a hold of the instance via the + // DebugElement and setting the value ourselves. + expect(() => { + const toggle = fixture.debugElement.query(By.css('mat-button-toggle')).componentInstance; + toggle.checked = true; + fixture.detectChanges(); + }).not.toThrow(); + }); + }); @Component({ diff --git a/src/material/button-toggle/button-toggle.ts b/src/material/button-toggle/button-toggle.ts index f0ded2976f62..3294fb30863b 100644 --- a/src/material/button-toggle/button-toggle.ts +++ b/src/material/button-toggle/button-toggle.ts @@ -183,7 +183,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After /** Selected button toggles in the group. */ get selected() { - const selected = this._selectionModel.selected; + const selected = this._selectionModel ? this._selectionModel.selected : []; return this.multiple ? selected : (selected[0] || null); } @@ -276,10 +276,14 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After (this.selected as MatButtonToggle).checked = false; } - if (select) { - this._selectionModel.select(toggle); + if (this._selectionModel) { + if (select) { + this._selectionModel.select(toggle); + } else { + this._selectionModel.deselect(toggle); + } } else { - this._selectionModel.deselect(toggle); + deferEvents = true; } // We need to defer in some cases in order to avoid "changed after checked errors", however @@ -294,7 +298,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After /** Checks whether a button toggle is selected. */ _isSelected(toggle: MatButtonToggle) { - return this._selectionModel.isSelected(toggle); + return this._selectionModel && this._selectionModel.isSelected(toggle); } /** Determines whether a button toggle should be checked on init. */