Reputation: 31
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
Upvotes: 3
Views: 3262
Reputation: 1178
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. Upvotes: 4