Skip to content

Commit bd24369

Browse files
crisbetojelbourn
authored andcommitted
fix(button-toggle): error when check value is set via static attribute in Ivy (#16587)
Fixes the button toggle throwing an error under Ivy, if its `checked` value is set via a static attribute (e.g. `<mat-button-toggle checked>`). 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.
1 parent 174bf40 commit bd24369

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

src/material/button-toggle/button-toggle.spec.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,20 @@ describe('MatButtonToggle without forms', () => {
845845
expect(fixture.componentInstance.toggles.toArray()[1].checked).toBe(false);
846846
expect(fixture.componentInstance.toggles.toArray()[2].checked).toBe(true);
847847
});
848+
849+
it('should not throw if initial value is set during creation', () => {
850+
const fixture = TestBed.createComponent(ButtonTogglesInsideButtonToggleGroupMultiple);
851+
852+
// In Ivy static inputs are set during creation. We simulate this by not calling
853+
// `fixture.detectChanges` immediately, but getting a hold of the instance via the
854+
// DebugElement and setting the value ourselves.
855+
expect(() => {
856+
const toggle = fixture.debugElement.query(By.css('mat-button-toggle')).componentInstance;
857+
toggle.checked = true;
858+
fixture.detectChanges();
859+
}).not.toThrow();
860+
});
861+
848862
});
849863

850864
@Component({

src/material/button-toggle/button-toggle.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
183183

184184
/** Selected button toggles in the group. */
185185
get selected() {
186-
const selected = this._selectionModel.selected;
186+
const selected = this._selectionModel ? this._selectionModel.selected : [];
187187
return this.multiple ? selected : (selected[0] || null);
188188
}
189189

@@ -276,10 +276,14 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
276276
(this.selected as MatButtonToggle).checked = false;
277277
}
278278

279-
if (select) {
280-
this._selectionModel.select(toggle);
279+
if (this._selectionModel) {
280+
if (select) {
281+
this._selectionModel.select(toggle);
282+
} else {
283+
this._selectionModel.deselect(toggle);
284+
}
281285
} else {
282-
this._selectionModel.deselect(toggle);
286+
deferEvents = true;
283287
}
284288

285289
// 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
294298

295299
/** Checks whether a button toggle is selected. */
296300
_isSelected(toggle: MatButtonToggle) {
297-
return this._selectionModel.isSelected(toggle);
301+
return this._selectionModel && this._selectionModel.isSelected(toggle);
298302
}
299303

300304
/** Determines whether a button toggle should be checked on init. */

0 commit comments

Comments
 (0)