Skip to content

Commit 96a9414

Browse files
committed
fix(button-toggle): static checked value not being picked up
Fixes the static checked value of a button toggle not having an effect in Ivy, because it ends up being assigned earlier than we expect. This is a side effect of the circular dependency between the toggle group and the toggle which should be cleaned up at some point, because it's not the first time it has caused issues with things going out of sync. Fixes #18427.
1 parent a58c725 commit 96a9414

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ describe('MatButtonToggle without forms', () => {
270270
RepeatedButtonTogglesWithPreselectedValue,
271271
ButtonToggleWithTabindex,
272272
ButtonToggleWithStaticName,
273+
ButtonToggleWithStaticChecked,
273274
],
274275
});
275276

@@ -880,6 +881,14 @@ describe('MatButtonToggle without forms', () => {
880881
}).not.toThrow();
881882
});
882883

884+
it('should be able to pre-check a button toggle using a static checked binding', () => {
885+
const fixture = TestBed.createComponent(ButtonToggleWithStaticChecked);
886+
fixture.detectChanges();
887+
888+
expect(fixture.componentInstance.toggles.map(t => t.checked)).toEqual([false, true]);
889+
expect(fixture.componentInstance.group.value).toBe('2');
890+
});
891+
883892
});
884893

885894
@Component({
@@ -1042,3 +1051,17 @@ class ButtonToggleWithTabindex {}
10421051
template: `<mat-button-toggle name="custom-name"></mat-button-toggle>`
10431052
})
10441053
class ButtonToggleWithStaticName {}
1054+
1055+
1056+
@Component({
1057+
template: `
1058+
<mat-button-toggle-group>
1059+
<mat-button-toggle value="1">One</mat-button-toggle>
1060+
<mat-button-toggle value="2" checked>Two</mat-button-toggle>
1061+
</mat-button-toggle-group>
1062+
`
1063+
})
1064+
class ButtonToggleWithStaticChecked {
1065+
@ViewChild(MatButtonToggleGroup) group: MatButtonToggleGroup;
1066+
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
1067+
}

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
294294
// the side-effect is that we may end up updating the model value out of sequence in others
295295
// The `deferEvents` flag allows us to decide whether to do it on a case-by-case basis.
296296
if (deferEvents) {
297-
Promise.resolve(() => this._updateModelValue(isUserInput));
297+
Promise.resolve().then(() => this._updateModelValue(isUserInput));
298298
} else {
299299
this._updateModelValue(isUserInput);
300300
}
@@ -502,16 +502,25 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit
502502
}
503503

504504
ngOnInit() {
505-
this._isSingleSelector = this.buttonToggleGroup && !this.buttonToggleGroup.multiple;
505+
const group = this.buttonToggleGroup;
506+
this._isSingleSelector = group && !group.multiple;
506507
this._type = this._isSingleSelector ? 'radio' : 'checkbox';
507508
this.id = this.id || `mat-button-toggle-${_uniqueIdCounter++}`;
508509

509510
if (this._isSingleSelector) {
510-
this.name = this.buttonToggleGroup.name;
511+
this.name = group.name;
511512
}
512513

513-
if (this.buttonToggleGroup && this.buttonToggleGroup._isPrechecked(this)) {
514-
this.checked = true;
514+
if (group) {
515+
if (group._isPrechecked(this)) {
516+
this.checked = true;
517+
} else if (group._isSelected(this) !== this._checked) {
518+
// As as side effect of the circular dependency between the toggle group and the button,
519+
// we may end up in a state where the button is supposed to be checked on init, but it
520+
// isn't, because the checked value was assigned too early. This can happen when Ivy
521+
// assigns the static input value before the `ngOnInit` has run.
522+
group._syncButtonToggle(this, this._checked);
523+
}
515524
}
516525

517526
this._focusMonitor.monitor(this._elementRef, true);

0 commit comments

Comments
 (0)