From 1143acb33615354c55c6613d114d1b6db72a1978 Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Tue, 15 Feb 2022 12:48:05 +0530 Subject: [PATCH 1/8] feat(checkbox): add control value accessor implementation --- .../src/checkbox/checkbox.component.ts | 56 +++++++++++++++---- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index e47bced19..fad5fb896 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 { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ @@ -8,31 +9,66 @@ 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; + } @Input() - public disabled: boolean | undefined; + public set disabled(disabled: boolean | undefined) { + this.isDisabled = disabled ?? false; + } @Output() public readonly checkedChange: EventEmitter = new EventEmitter(); + public isChecked: boolean = false; + public isDisabled: boolean = false; + + private onTouched: () => void = () => {}; + private onChanged: (value: boolean) => void = () => {}; + 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: any): void { + this.onChanged = fn; + } + + public registerOnTouched(fn: any): void { + this.onTouched = fn; + } + + public setDisabledState(isDisabled: boolean): void { + this.isDisabled = isDisabled; + } + + public writeValue(isChecked: boolean): void { + this.isChecked = isChecked; } } From 9f3b630024b0b8ca96d642fed3579401ea9cf76a Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Tue, 15 Feb 2022 12:52:19 +0530 Subject: [PATCH 2/8] test(checkbox): add supporting test cases for control value accessor --- .../src/checkbox/checkbox.component.test.ts | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) 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); + }); }); From 0cc270ce30450823c669f23b71e1f614626b011c Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Tue, 15 Feb 2022 13:55:54 +0530 Subject: [PATCH 3/8] feat(checkbox): fix lint issue --- projects/components/src/checkbox/checkbox.component.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index fad5fb896..d29d11288 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -46,8 +46,8 @@ export class CheckboxComponent implements ControlValueAccessor { public isChecked: boolean = false; public isDisabled: boolean = false; - private onTouched: () => void = () => {}; - private onChanged: (value: boolean) => void = () => {}; + private onTouched!: () => void; + private onChanged!: (value: boolean) => void; public onCheckboxChange(event: MatCheckboxChange): void { this.isChecked = event.checked; @@ -56,11 +56,11 @@ export class CheckboxComponent implements ControlValueAccessor { this.onTouched(); } - public registerOnChange(fn: any): void { + public registerOnChange(fn: (value: boolean) => void): void { this.onChanged = fn; } - public registerOnTouched(fn: any): void { + public registerOnTouched(fn: () => void): void { this.onTouched = fn; } From 24a94c1570f6ec15cc729b49495ef9f8b5bbbfb0 Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Thu, 17 Feb 2022 15:38:13 +0530 Subject: [PATCH 4/8] fix(checkbox): type coercion fix --- projects/components/src/checkbox/checkbox.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index d29d11288..ba8313817 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -68,7 +68,7 @@ export class CheckboxComponent implements ControlValueAccessor { this.isDisabled = isDisabled; } - public writeValue(isChecked: boolean): void { - this.isChecked = isChecked; + public writeValue(isChecked: boolean | undefined): void { + this.isChecked = isChecked ?? false; } } From c945ce2624489ab633a80517538a62145a0b49ff Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Fri, 18 Feb 2022 20:58:18 +0530 Subject: [PATCH 5/8] feat(checkbox): add change detection --- projects/components/src/checkbox/checkbox.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index ba8313817..a0d080f78 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -1,4 +1,4 @@ -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'; @@ -49,6 +49,8 @@ export class CheckboxComponent implements ControlValueAccessor { private onTouched!: () => void; private onChanged!: (value: boolean) => void; + public constructor(private readonly cdr: ChangeDetectorRef) {} + public onCheckboxChange(event: MatCheckboxChange): void { this.isChecked = event.checked; this.checkedChange.emit(this.isChecked); @@ -66,9 +68,11 @@ export class CheckboxComponent implements ControlValueAccessor { public setDisabledState(isDisabled: boolean): void { this.isDisabled = isDisabled; + this.cdr.markForCheck(); } public writeValue(isChecked: boolean | undefined): void { this.isChecked = isChecked ?? false; + this.cdr.markForCheck(); } } From 377899c411dd5885e346578a80fbd57e45bd42ee Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Mon, 21 Feb 2022 12:28:40 +0530 Subject: [PATCH 6/8] fix(checkbox): add checked getter --- projects/components/src/checkbox/checkbox.component.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index a0d080f78..6ea4b2ca3 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -43,6 +43,10 @@ export class CheckboxComponent implements ControlValueAccessor { @Output() public readonly checkedChange: EventEmitter = new EventEmitter(); + public get checked(): boolean { + return this.isChecked; + } + public isChecked: boolean = false; public isDisabled: boolean = false; From 637da6048f25ca47aeeb719526d9981dcfb51095 Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Mon, 21 Feb 2022 12:30:03 +0530 Subject: [PATCH 7/8] fix(checkbox): add disabled getter --- projects/components/src/checkbox/checkbox.component.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index 6ea4b2ca3..38485e67c 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -47,6 +47,10 @@ export class CheckboxComponent implements ControlValueAccessor { return this.isChecked; } + public get disabled(): boolean { + return this.isDisabled; + } + public isChecked: boolean = false; public isDisabled: boolean = false; From 8d8f4622ac28b2a7fc93c559e3be5ab3c9d36d2d Mon Sep 17 00:00:00 2001 From: Adithya Sreyaj Date: Mon, 21 Feb 2022 19:21:56 +0530 Subject: [PATCH 8/8] fix(checkbox): fix linting issue --- .../components/src/checkbox/checkbox.component.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/projects/components/src/checkbox/checkbox.component.ts b/projects/components/src/checkbox/checkbox.component.ts index 38485e67c..bc4cb2753 100644 --- a/projects/components/src/checkbox/checkbox.component.ts +++ b/projects/components/src/checkbox/checkbox.component.ts @@ -35,22 +35,22 @@ export class CheckboxComponent implements ControlValueAccessor { this.isChecked = checked ?? false; } + public get checked(): boolean { + return this.isChecked; + } + @Input() public set disabled(disabled: boolean | undefined) { this.isDisabled = disabled ?? false; } - @Output() - public readonly checkedChange: EventEmitter = new EventEmitter(); - - public get checked(): boolean { - return this.isChecked; - } - public get disabled(): boolean { return this.isDisabled; } + @Output() + public readonly checkedChange: EventEmitter = new EventEmitter(); + public isChecked: boolean = false; public isDisabled: boolean = false;