Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 CheckboxControlValueAccessor implements

Tags:

angular

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

like image 249
j.nord Avatar asked Dec 05 '25 10:12

j.nord


1 Answers

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:

  1. controlID must be unique, which can be accomplished as shown using a static counter.
  2. I decided against making checked be an Input() variable, since you can accomplish the same thing with outer ngModel variables.
  3. Readonly and other functionality has been omitted for simplicity.
like image 78
Kent Weigel Avatar answered Dec 08 '25 02:12

Kent Weigel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!