Skip to content

Commit

Permalink
fix(module:radio): emit false to the ngModel whenever the radio b…
Browse files Browse the repository at this point in the history
…utton is deselected (#7270)
  • Loading branch information
arturovt committed Feb 25, 2022
1 parent e95d941 commit 2704237
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 6 deletions.
25 changes: 19 additions & 6 deletions components/radio/radio.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
Component,
ElementRef,
forwardRef,
Inject,
Input,
NgZone,
OnDestroy,
Expand Down Expand Up @@ -88,7 +89,7 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
isRadioButton = !!this.nzRadioButtonDirective;
onChange: OnChangeType = () => {};
onTouched: OnTouchedType = () => {};
@ViewChild('inputElement', { static: false }) inputElement?: ElementRef;
@ViewChild('inputElement', { static: true }) inputElement!: ElementRef<HTMLInputElement>;
@Input() nzValue: NzSafeAny | null = null;
@Input() @InputBoolean() nzDisabled = false;
@Input() @InputBoolean() nzAutoFocus = false;
Expand All @@ -109,8 +110,8 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
private cdr: ChangeDetectorRef,
private focusMonitor: FocusMonitor,
@Optional() private directionality: Directionality,
@Optional() private nzRadioService: NzRadioService,
@Optional() private nzRadioButtonDirective: NzRadioButtonDirective
@Optional() @Inject(NzRadioService) private nzRadioService: NzRadioService | null,
@Optional() @Inject(NzRadioButtonDirective) private nzRadioButtonDirective: NzRadioButtonDirective | null
) {}

setDisabledState(disabled: boolean): void {
Expand Down Expand Up @@ -143,7 +144,21 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
this.cdr.markForCheck();
});
this.nzRadioService.selected$.pipe(takeUntil(this.destroy$)).subscribe(value => {
const isChecked = this.isChecked;
this.isChecked = this.nzValue === value;
// We don't have to run `onChange()` on each `nz-radio` button whenever the `selected$` emits.
// If we have 8 `nz-radio` buttons within the `nz-radio-group` and they're all connected with
// `ngModel` or `formControl` then `onChange()` will be called 8 times for each `nz-radio` button.
// We prevent this by checking if `isChecked` has been changed or not.
if (
this.isNgModel &&
isChecked !== this.isChecked &&
// We're only intereted if `isChecked` has been changed to `false` value to emit `false` to the ascendant form,
// since we already emit `true` within the `setupClickListener`.
this.isChecked === false
) {
this.onChange(false);
}
this.cdr.markForCheck();
});
}
Expand Down Expand Up @@ -193,9 +208,7 @@ export class NzRadioComponent implements ControlValueAccessor, AfterViewInit, On
return;
}
this.ngZone.run(() => {
if (this.nzRadioService) {
this.nzRadioService.select(this.nzValue);
}
this.nzRadioService?.select(this.nzValue);
if (this.isNgModel) {
this.isChecked = true;
this.onChange(true);
Expand Down
56 changes: 56 additions & 0 deletions components/radio/radio.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('radio', () => {
NzTestRadioGroupFormComponent,
NzTestRadioGroupDisabledComponent,
NzTestRadioGroupDisabledFormComponent,
NzTestRadioGroupLabelNgModelComponent,
NzTestRadioSingleRtlComponent,
NzTestRadioGroupRtlComponent,
NzTestRadioButtonRtlComponent
Expand Down Expand Up @@ -322,6 +323,30 @@ describe('radio', () => {
}).not.toThrow();
}));
});
describe('ngModel on the `nz-radio` button', () => {
it('`onChange` of each `nz-radio` should emit correct values', () => {
const fixture = TestBed.createComponent(NzTestRadioGroupLabelNgModelComponent);
fixture.detectChanges();

const radios = fixture.debugElement.queryAll(By.directive(NzRadioComponent));

radios[0].nativeElement.click();
expect(fixture.componentInstance.items).toEqual([
{ label: 'A', checked: true },
{ label: 'B', checked: false },
{ label: 'C', checked: false },
{ label: 'D', checked: false }
]);

radios[1].nativeElement.click();
expect(fixture.componentInstance.items).toEqual([
{ label: 'A', checked: false },
{ label: 'B', checked: true },
{ label: 'C', checked: false },
{ label: 'D', checked: false }
]);
});
});
describe('RTL', () => {
it('should single radio className correct', () => {
const fixture = TestBed.createComponent(NzTestRadioSingleRtlComponent);
Expand Down Expand Up @@ -520,6 +545,37 @@ export class NzTestRadioGroupSolidComponent {
singleDisabled = false;
}

/** https://github.com/NG-ZORRO/ng-zorro-antd/issues/7254 */
@Component({
template: `
<nz-radio-group>
<label nz-radio *ngFor="let item of items" [nzValue]="item.label" [(ngModel)]="item.checked">
{{ item.label }}
</label>
</nz-radio-group>
`
})
export class NzTestRadioGroupLabelNgModelComponent {
items = [
{
label: 'A',
checked: false
},
{
label: 'B',
checked: false
},
{
label: 'C',
checked: false
},
{
label: 'D',
checked: false
}
];
}

@Component({
template: `
<div [dir]="direction">
Expand Down

0 comments on commit 2704237

Please sign in to comment.