import { OnInit, Optional, Self, OnDestroy } from '@angular/core'; import { ControlValueAccessor, NgControl } from '@angular/forms'; import { TypedFormGroup, Controls } from './forms-typed'; import { forEachControlIn } from './forms-util'; import { Subscription } from 'rxjs'; export class ControlValueAccessorConnector<T, C extends Controls<T> = Controls<T>> implements OnInit, OnDestroy, ControlValueAccessor { protected subs = new Subscription(); protected touchIsChildInitiated: boolean; public form: TypedFormGroup<T, C>; constructor(@Optional() @Self() private directive: NgControl, form: TypedFormGroup<T, C>) { if (directive) { directive.valueAccessor = this; } this.form = form; } ngOnInit(): void { if (this.directive && this.directive.control) { forEachControlIn(this.form) .markAsTouchedSimultaneouslyWith(this.directive.control, () => this.touchIsChildInitiated) .addValidatorsTo(this.directive.control); } const values = this.form.valueChanges.subscribe(v => this.onChange(v)); const statuses = this.form.statusChanges.subscribe(s => { if (this.form.touched) { this.onTouch(); } }); this.subs.add(values); this.subs.add(statuses); } ngOnDestroy(): void { this.subs.unsubscribe(); } protected onChange = (_: T) => { }; protected onTouch = () => { }; writeValue(obj: any): void { this.form.patchValue(obj || {}); } registerOnChange(fn: any): void { this.onChange = fn; } registerOnTouched(fn: any): void { this.onTouch = () => { this.touchIsChildInitiated = true; fn(); this.touchIsChildInitiated = false; }; } setDisabledState(disable: boolean) { disable ? this.form.disable() : this.form.enable(); forEachControlIn(this.form).call(disable ? 'disable' : 'enable'); } }