ngx-checkbox-list
Checkbox list form control for Angular X
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';import { Input, Component, forwardRef } from '@angular/core';import { Option } from './option'; @Component({ selector: 'ngx-checkbox-list', // eslint-disable-next-line @typescript-eslint/no-use-before-define providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CheckboxListComponent), multi: true }], template: ` <div [ngClass]="classList"> <div [class]="itemClassName" *ngFor="let o of options; let i = index"> <input type="checkbox" [value]="o.value" [checked]="checked(o.value)" [attr.id]="name + i" (change)="change($event)" /> <label [attr.for]="name + i">{{ o.label }}</label> </div> </div> `,})export class CheckboxListComponent implements ControlValueAccessor { /** * Used as prefix to generate unique label/id */ @Input() name = ''; /** * Key/value pairs to produce ui option label and value */ @Input() options: Option[]; /** * Used to format returning value as object of ids */ @Input() objectId?: string; @Input() classList: string[] | string = 'checkbox-list'; /** * Name of propery for case when need return object with ids */ @Input() objectKey?: string; /** * Input/label will be wrapped into div with this class name */ @Input() itemClassName = ''; private value?: string[]; private onTouched: (_: unknown) => void; private onChange: (_: unknown) => void; /** * Checks if value is selected (checkbox will be mark as checked) */ checked(value: unknown): boolean { if (!this.value) { return false; } return this.value.includes(String(value)); } /** * Called when one of checkbox value changed */ change(event: Event) { const input = event.target as HTMLInputElement; const inputValue = String(input.value); if (!Array.isArray(this.value)) { this.value = []; } this.value = input.checked ? [...this.value, inputValue] : this.value.filter(v => v !== inputValue); let formValue: unknown[] = this.value; if (this.objectId && this.objectKey) { // If objectId and objectKey are defined, we return {[objectId]: value, [objectKey]: label }[] const id = this.objectId; const name = this.objectKey; // Converts array of values to array of objects. formValue = this.options .filter(o => (this.value as string[]).includes(String(o.value))) .map(o => ({ [id]: o.value, [name]: o.label })); } else if (this.objectId) { // If objectId is defined, we return { [id]: o.value }[] const id = this.objectId; formValue = this.options .filter(o => (this.value as string[]).includes(String(o.value))) .map(o => ({ [id]: o.value })); } else { formValue = formValue.filter((value, index, self) => index === self.findIndex(other => other === value)); } this.onChange(formValue); } // Form ControlValueAccessor interface /** * Write a new value to the element */ // eslint-disable-next-line @typescript-eslint/no-explicit-any writeValue(value: any) { if (!Array.isArray(value)) { value = value ? [] : null; // eslint-disable-line @typescript-eslint/tslint/config // eslint-disable-next-line wix-editor/prefer-ternary } else if (this.objectId) { value = value.map(v => String(v[this.objectId as string])); } else { value = value.map(v => String(v)); // eslint-disable-line @typescript-eslint/tslint/config } this.value = value; } /** * Set the function to be called when the control receives a change event */ registerOnChange(fn: (_: unknown) => void) { this.onChange = fn; } /** * Set the function to be called when the control receives a touch event */ registerOnTouched(fn: (_: unknown) => void) { this.onTouched = fn; }}