import {Component, ContentChildren, forwardRef, Input, QueryList} from '@angular/core'; import {ControlContainer, ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm} from '@angular/forms'; @Component({ selector: 'app-smiley', template: '
' }) export class SmileyComponent { @Input() label = ''; @Input() value: number|undefined; @Input() icon = ''; checked = false; } export const APP_SMILEY_SELECT_CONTROL_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SmileySelectComponent), multi: true }; @Component({ selector: 'app-smiley-select', templateUrl: './smiley-select.component.html', styleUrls: ['./smiley-select.component.scss'], providers: [APP_SMILEY_SELECT_CONTROL_VALUE_ACCESSOR], viewProviders: [ { provide: ControlContainer, useExisting: NgForm } ], }) export class SmileySelectComponent implements ControlValueAccessor { @ContentChildren(SmileyComponent, {descendants: true}) smileys: QueryList|undefined; private innerModel: number|undefined; private dirtyAble = false; private onChangeCallback: (newValue: number|undefined) => any = () => {}; private onTouchedCallback: () => any = () => {}; constructor() { } get options(): SmileyComponent[] { if (this.smileys) { return [...this.smileys.toArray()]; } return []; } get selectedText(): string { return this.options.find(x => x.checked)?.label || ''; } get value(): number|undefined { return this.innerModel; } set value(value: number|undefined) { if (value !== this.innerModel) { this.innerModel = value; if (this.dirtyAble) { this.onChangeCallback(value); } } } handleClick(smiley: SmileyComponent): void { this.makeDirtyable(); this.options.forEach(x => x.checked = false); smiley.checked = true; this.value = smiley.value; } makeDirtyable(): void { this.dirtyAble = true; } registerOnChange(fn: any): void { this.onChangeCallback = fn; } registerOnTouched(fn: any): void { this.onTouchedCallback = fn; } writeValue(newValue: any): void { this.value = newValue; } }