@deepkit/desktop-ui
Version:
Library for desktop UI widgets in Angular 10+
115 lines (91 loc) • 3.15 kB
text/typescript
import { Directive, forwardRef, HostBinding, inject, Injector, Input, input, model, OnDestroy, Type } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';
import { FormComponent } from '../components/form/form.component';
export function ngValueAccessor<T>(clazz: Type<T>) {
return {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => clazz),
multi: true,
};
}
export class ValueAccessorBase<T> implements ControlValueAccessor, OnDestroy {
private _ngControl?: NgControl;
private _ngControlFetched = false;
value = model<T | undefined>(undefined);
disabled = model(false);
valid?: boolean;
error?: boolean;
protected formComponent?: FormComponent;
protected _changedCallback: ((value: T | undefined) => void)[] = [];
protected _touchedCallback: (() => void)[] = [];
get isDisabled(): boolean {
if (this.formComponent && this.formComponent.disabled()) return true;
if (this.ngControl) {
return !!this.ngControl.disabled;
}
return this.disabled();
}
get isValid() {
return this.valid === true;
}
get isError() {
if (undefined === this.error && this.ngControl) {
return (this.ngControl.dirty || this.ngControl.touched) && this.ngControl.invalid;
}
return this.error;
}
required = input(false);
protected injector = inject(Injector);
get ngControl(): NgControl | undefined {
if (!this._ngControlFetched) {
try {
this._ngControl = this.injector.get(NgControl);
} catch (e) {
}
this._ngControlFetched = true;
}
return this._ngControl;
}
setDisabledState(isDisabled: boolean): void {
this.disabled.set(isDisabled);
}
ngOnDestroy(): void {
}
/**
* This is called whenever value() needs to update. Either through Angular forms or through setValue().
* Do not call this method in UI code, use setValue() instead so that angular forms informed about the change.
*
* This is a good place to normalize values whenever they change. (like clamping a number to a range)
*/
writeValue(value?: T) {
this.value.set(value);
}
/**
* Set the value from UI code.
*/
setValue(value: T | undefined) {
this.writeValue(value);
for (const callback of this._changedCallback) {
callback(this.value());
}
}
/**
* Call this method to signal Angular's form or other users that this widget has been touched.
*/
touch() {
for (const callback of this._touchedCallback) {
callback();
}
}
registerOnChange(fn: (value: T | undefined) => void) {
this._changedCallback.push(fn);
}
registerOnTouched(fn: () => void) {
this._touchedCallback.push(fn);
}
}