When we implement the CheckboxControlValueAccessor we get the follow error:
Types have separate declarations of a private property '_renderer'
Code:
export class NHCheckbox implements CheckboxControlValueAccessor {
_align = "right";
_label = ""; // Label
_required = false;
_tooltip: string = null;
constructor(
private _renderer: Renderer,
private _elementRef: ElementRef
) {
}
CheckboxControlValueAccessor class:
export declare class CheckboxControlValueAccessor implements ControlValueAccessor {
private _renderer;
private _elementRef;
onChange: (_: any) => void;
onTouched: () => void;
constructor(_renderer: Renderer, _elementRef: ElementRef);
writeValue(value: any): void;
registerOnChange(fn: (_: any) => {}): void;
registerOnTouched(fn: () => {}): void;
setDisabledState(isDisabled: boolean): void;
}
What are we doing wrong?
Angular Version: 4.1.3 Typescript: 2.3.4
When I needed a checkbox component in Angular 2+, it seemed intuitive to do the same thing that you are trying to do. Why start with a general control when you can start with a checkbox, right? After spending too much time on it, I decided to relent and use ControlValueAccessor instead.
As you can see in this plnkr, the checkbox component can be written like this:
import { Component, /*Input,*/ Renderer, ElementRef, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'my-checkbox',
template: `
<div class="checkbox-container">
<input type="checkbox" id="{{ controlID }}"
[checked]="checked" (change)="onChange($event)" />
<label for="{{ controlID }}"></label>
</div>
`,
styles: [`
.checkbox-container {
background-color: #ddd;
width: 20px;
height: 20px;
position: relative;
}
`, `
.checkbox-container input[type="checkbox"] {
visibility: hidden;
}
`, `
.checkbox-container label {
width: 18px;
height: 18px;
position: absolute;
top: 1px;
left: 1px;
background-color: white;
}
`,`
.checkbox-container label:before {
content: '';
width: 16px;
height: 8px;
border: 4px solid #000;
position: absolute;
border-top: none;
border-right: none;
transform: rotate(-50deg);
top: 1px;
left: 1px;
opacity: 0;
}
`, `
.checkbox-container input[type="checkbox"]:checked + label:before {
opacity: 1;
}
`],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CheckboxComponent),
multi: true
}
]
})
export class CheckboxComponent implements ControlValueAccessor {
static idCounter: Number = 0;
controlID: String;
//@Input() checked: Boolean;
checked: Boolean;
constructor(private renderer: Renderer, private elementRef: ElementRef) {
this.controlID = "myCheckbox" + CheckboxComponent.idCounter++;
}
propagateChange = (_: any) => { };
onTouchedCallback: () => {};
writeValue(value: any) {
if ((value !== undefined) && (value !== null)) {
this.checked = value;
}
}
registerOnChange(fn: any) {
this.propagateChange = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
};
onChange(event) {
this.checked = event.target.checked;
this.propagateChange(event.target.checked);
}
}
and can be used like this:
<form #form="ngForm" (ngSubmit)="submit(form.value)">
<div>
<h2>Checkbox Demo Using {{ framework }}</h2>
</div>
<div>
<my-checkbox name="b1" [(ngModel)]="b1"></my-checkbox>
<my-checkbox name="b2" [(ngModel)]="b2"></my-checkbox>
<my-checkbox name="b3" [(ngModel)]="b3"></my-checkbox>
</div>
</form>
<pre>{{ form.value | json }}</pre>
Notes:
controlID must be unique, which can be accomplished as shown using a static counter. checked be an
Input() variable, since you can accomplish the same thing with outer ngModel variables. If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With