У меня есть простая группа FormGroup, как это:
const form = this.fb.group({
type: ['', { validators: Validators.required, updateOn: 'change' }],
doc_no: ['', Validators.required],
currency: ['', Validators.required],
exchange_rate: [1, Validators.required],
...
При работе с простым HTML вводом, подобным этому:
<input formControlName="exchange_rate" />
В этом случае, когда я очищаю входное значение, Angular обрабатывает Validators.required должным образом, и ввод получает ng-invalid
класс, а также вся форма попадает в недопустимое состояние.
Однако, когда я перехожу к пользовательскому элементу управления (в основном это простой упакованный ввод с предопределенными преобразованиями и некоторые другие методы, такие как:
<app-input-number formControlName="exchange_rate" ></app-input-number>
Angular не устанавливает недопустимый класс ng при очистке значения. Однако, когда я изменяю значение или даже просто фокусирую ввод, Angular устанавливает атрибут ng-touch.
Я явно что-то упустил. Могу ли я получить подсказку?
input-number.component. html:
<input class="form-control"
type="text"
[value]="number | decimal2:'0.0-8'"
(change)="onChange($event)"
(blur)="onBlur($event)"
[disabled]="disabled"
[readonly]="readonly"
[required]="required"
>
input -number.component.ts:
import { Component, Input, Output, forwardRef, EventEmitter, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validator, ControlValueAccessor, FormControl, ValidationErrors } from '@angular/forms';
import { Converter } from '@app/core/';
@Component({
selector: 'app-input-number',
templateUrl: './input-number.component.html',
styleUrls: ['./input-number.component.scss'],
encapsulation: ViewEncapsulation.None,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => InputNumberComponent),
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => InputNumberComponent),
multi: true,
}
]
})
export class InputNumberComponent implements Validator, ControlValueAccessor {
@Input()
disabled = false;
@Input()
readonly = false;
@Input()
required = false;
@Input()
number?: number;
@Output()
numberChange = new EventEmitter<number>();
constructor(
private converts: Converter
) {
}
onChange(event?: any) {
if (this.disabled) {
return;
}
const _value = event.target.value;
const _number = this.converts.toNumber(_value);
if (!_number) {
return;
}
this.processChange(_value);
}
private processChange(value: any) {
if (!value || value === '') {
this.number = null;
this.numberChange.emit(null);
this.onChanged(null);
return;
}
let _number: number;
try {
_number = this.converts.toNumber(value);
} catch (ex) {
return;
}
this.number = _number;
this.numberChange.emit(_number);
this.onChanged(_number);
}
// ControlValueAccessor INTERFACE
// the method set in registerOnChange, it is just
// a placeholder for a method that takes one parameter,
// we use it to emit changes back to the form
private onChanged = (_: any) => { };
private onTouched = () => { };
onBlur(event?: any) {
this.onTouched();
}
// this is the initial value set to the component
writeValue(value: any): void {
if (this.disabled) {
return;
}
if (value !== this.number) {
try {
if (!isNaN(value)) {
this.number = (+value);
return;
}
this.number = this.converts.toNumber(value);
// const _number = this.converts.toNumber(value);
// this.number = this.converts.toString(_number);
} catch (ex) {
this.number = null;
return;
}
}
}
// registers 'fn' that will be fired when changes are made
// this is how we emit the changes back to the form
registerOnChange(fn: any): void {
this.onChanged = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
// VALIDATOR INTERFACE
validate(control: FormControl): ValidationErrors {
if (this.required && !this.number) {
return {
invalid: true
};
}
return null;
}
registerOnValidatorChange?(fn: () => void): void {
// console.log('registerOnValidatorChange', fn);
}
}
Спасибо