Skip to content

Commit

Permalink
fix(button-toggle): static checked value not being picked up (angular…
Browse files Browse the repository at this point in the history
…#18442)

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 angular#18427.
  • Loading branch information
crisbeto committed Apr 23, 2020
1 parent e46afe8 commit 7f7e0a1
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 5 deletions.
23 changes: 23 additions & 0 deletions src/material/button-toggle/button-toggle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ describe('MatButtonToggle without forms', () => {
RepeatedButtonTogglesWithPreselectedValue,
ButtonToggleWithTabindex,
ButtonToggleWithStaticName,
ButtonToggleWithStaticChecked,
],
});

Expand Down Expand Up @@ -888,6 +889,14 @@ describe('MatButtonToggle without forms', () => {
.toBe(true);
});

it('should be able to pre-check a button toggle using a static checked binding', () => {
const fixture = TestBed.createComponent(ButtonToggleWithStaticChecked);
fixture.detectChanges();

expect(fixture.componentInstance.toggles.map(t => t.checked)).toEqual([false, true]);
expect(fixture.componentInstance.group.value).toBe('2');
});

});

@Component({
Expand Down Expand Up @@ -1050,3 +1059,17 @@ class ButtonToggleWithTabindex {}
template: `<mat-button-toggle name="custom-name"></mat-button-toggle>`
})
class ButtonToggleWithStaticName {}


@Component({
template: `
<mat-button-toggle-group>
<mat-button-toggle value="1">One</mat-button-toggle>
<mat-button-toggle value="2" checked>Two</mat-button-toggle>
</mat-button-toggle-group>
`
})
class ButtonToggleWithStaticChecked {
@ViewChild(MatButtonToggleGroup) group: MatButtonToggleGroup;
@ViewChildren(MatButtonToggle) toggles: QueryList<MatButtonToggle>;
}
19 changes: 14 additions & 5 deletions src/material/button-toggle/button-toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
// the side-effect is that we may end up updating the model value out of sequence in others
// The `deferEvents` flag allows us to decide whether to do it on a case-by-case basis.
if (deferEvents) {
Promise.resolve(() => this._updateModelValue(isUserInput));
Promise.resolve().then(() => this._updateModelValue(isUserInput));
} else {
this._updateModelValue(isUserInput);
}
Expand Down Expand Up @@ -502,16 +502,25 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit
}

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

if (this._isSingleSelector) {
this.name = this.buttonToggleGroup.name;
this.name = group.name;
}

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

this._focusMonitor.monitor(this._elementRef, true);
Expand Down

0 comments on commit 7f7e0a1

Please sign in to comment.