import {
Component,
ChangeDetectorRef,
Input,
ViewChild,
forwardRef,
OnInit,
AfterViewInit,
inject,
} from "@angular/core";
import { LabelWrapper } from "../../wrappers/label-wrapper/label-wrapper.component";
import {
NG_VALUE_ACCESSOR,
ControlValueAccessor,
FormControl,
Validators,
ValidatorFn,
} from "@angular/forms";
import { SamFormService, SamFormEvent } from "../../form-service";
/**
*
*/
@Component({
selector: "sam-number",
template: `
`,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SamNumberComponent),
multi: true,
},
],
standalone: false,
})
export class SamNumberComponent
implements ControlValueAccessor, OnInit, AfterViewInit
{
private samFormService = inject(SamFormService);
private cdr = inject(ChangeDetectorRef);
/**
* (deprecated) sets value
*/
@Input() value: number;
/**
* sets the label wrapper text
*/
@Input() label: string;
/**
* sets the input name attribute value
*/
@Input() name: string;
/**
* sets the minimum allowed value
*/
@Input() min: number;
/**
* sets the maximum allowed value
*/
@Input() max: number;
/**
* sets the hint text
*/
@Input() hint: string;
/**
* deprecated, sets the error message manually
*/
@Input() errorMessage: string;
/**
* sets the disabled state
*/
@Input() disabled: boolean;
/**
* deprecated, toggles the required text in the label wrapper
*/
@Input() required: boolean;
/**
* sets the form control to trigger label wrapper messages
*/
@Input() control: FormControl;
/**
* Toggles validations to display with SamFormService events
*/
@Input() useFormService: boolean;
@ViewChild(LabelWrapper, { static: true }) public wrapper: LabelWrapper;
public invalidKeys = ["e", "E", ",", "-", "+"];
public onChange: (value: number) => void = () => {
this.wrapper.formatErrors(this.control);
};
public onTouched: () => void = () => undefined;
ngOnInit() {
if (!this.name) {
throw new Error(
" requires a [name] parameter\
for 508 compliance"
);
}
if (!this.control) {
return;
}
const validators: ValidatorFn[] = [];
if (this.control.validator) {
validators.push(this.control.validator);
}
if (this.required) {
validators.push(Validators.required);
}
this.control.setValidators(validators);
if (!this.useFormService) {
this.control.statusChanges.subscribe(() => {
this.wrapper.formatErrors(this.control);
this.cdr.detectChanges();
});
} else {
this.samFormService.formEventsUpdated$.subscribe((evt: SamFormEvent) => {
if (
(!evt.root || evt.root === this.control.root) &&
evt.eventType &&
evt.eventType === "submit"
) {
this.wrapper.formatErrors(this.control);
} else if (
(!evt.root || evt.root === this.control.root) &&
evt.eventType &&
evt.eventType === "reset"
) {
this.wrapper.clearError();
}
});
}
}
ngAfterViewInit() {
if (this.control) {
this.wrapper.formatErrors(this.control);
this.cdr.detectChanges();
}
}
keyDownHandler(event: KeyboardEvent) {
if (this.invalidKeys.indexOf(event.key) !== -1) {
event.preventDefault();
}
}
onInputChange(value: string) {
const parsed = value === "" ? null : Number(value);
this.value = parsed;
this.onChange(parsed);
}
registerOnChange(fn: (value: number) => void) {
this.onChange = fn;
}
registerOnTouched(fn: () => void) {
this.onTouched = fn;
}
setDisabledState(disabled: boolean) {
this.disabled = disabled;
}
writeValue(value: number) {
this.value = value;
}
}