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; } }