diff --git a/projects/components/src/checkbox/checkbox.component.test.ts b/projects/components/src/checkbox/checkbox.component.test.ts index 20850401c..c10523773 100644 --- a/projects/components/src/checkbox/checkbox.component.test.ts +++ b/projects/components/src/checkbox/checkbox.component.test.ts @@ -1,4 +1,5 @@ import { fakeAsync } from '@angular/core/testing'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { RouterTestingModule } from '@angular/router/testing'; import { createHostFactory, Spectator } from '@ngneat/spectator/jest'; import { CheckboxComponent } from './checkbox.component'; @@ -9,7 +10,7 @@ describe('Checkbox component', () => { const createHost = createHostFactory({ component: CheckboxComponent, - imports: [TraceCheckboxModule, RouterTestingModule], + imports: [TraceCheckboxModule, RouterTestingModule, ReactiveFormsModule], providers: [], declareComponent: false }); @@ -52,12 +53,32 @@ describe('Checkbox component', () => { // Click will toggle the values to true spectator.click(inputElement); - expect(spectator.component.checked).toBe(true); + expect(spectator.component.isChecked).toBe(true); expect(checkboxChangeSpy).toHaveBeenCalledWith(true); // Click will toggle the values to false spectator.click(inputElement); - expect(spectator.component.checked).toBe(false); + expect(spectator.component.isChecked).toBe(false); expect(checkboxChangeSpy).toHaveBeenCalledWith(false); })); + + test('should work correctly with control value accessor', () => { + const formControl = new FormControl(false); + spectator = createHost( + ` + `, + { + hostProps: { + formControl: formControl + } + } + ); + expect(spectator.component.isChecked).toBe(false); + + formControl.setValue(true); + expect(spectator.component.isChecked).toBe(true); + + formControl.disable(); + expect(spectator.component.isDisabled).toBe(true); + }); }); diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index e47bced19..bc4cb2753 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -1,4 +1,5 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ @@ -8,31 +9,78 @@ import { MatCheckboxChange } from '@angular/material/checkbox'; template: ` - ` + `, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: CheckboxComponent, + multi: true + } + ] }) -export class CheckboxComponent { +export class CheckboxComponent implements ControlValueAccessor { @Input() public label?: string; @Input() - public checked: boolean | undefined; + public set checked(checked: boolean | undefined) { + this.isChecked = checked ?? false; + } + + public get checked(): boolean { + return this.isChecked; + } @Input() - public disabled: boolean | undefined; + public set disabled(disabled: boolean | undefined) { + this.isDisabled = disabled ?? false; + } + + public get disabled(): boolean { + return this.isDisabled; + } @Output() public readonly checkedChange: EventEmitter = new EventEmitter(); + public isChecked: boolean = false; + public isDisabled: boolean = false; + + private onTouched!: () => void; + private onChanged!: (value: boolean) => void; + + public constructor(private readonly cdr: ChangeDetectorRef) {} + public onCheckboxChange(event: MatCheckboxChange): void { - this.checked = event.checked; - this.checkedChange.emit(this.checked); + this.isChecked = event.checked; + this.checkedChange.emit(this.isChecked); + this.onChanged(this.isChecked); + this.onTouched(); + } + + public registerOnChange(fn: (value: boolean) => void): void { + this.onChanged = fn; + } + + public registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + public setDisabledState(isDisabled: boolean): void { + this.isDisabled = isDisabled; + this.cdr.markForCheck(); + } + + public writeValue(isChecked: boolean | undefined): void { + this.isChecked = isChecked ?? false; + this.cdr.markForCheck(); } }