Вот моя форма ниже: Текущие проверки ошибок в форме не работают.
<div formGroupName = "deliveryAddress">
<div class = "row mb-4">
<div class = "col mb-4">
<label class = "form-label">First Name</label>
<input id = "firstName" class = "form-control fw-bold" type = "text" formControlName = "firstName"
(change) = "saveToDataStore()">
<div *ngIf = "firstName.invalid && (firstName.dirty || firstName.touched)" class = "alert alert-danger">
<div *ngIf = "firstName.hasError('required')">
First Name is required.
</div>
</div>
</div>
<div class = "col mb-4">
<label class = "form-label">Last Name</label>
<input id = "lastName" class = "form-control fw-bold" type = "text" formControlName = "lastName"
(change) = "saveToDataStore()">
<div *ngIf = "lastName.invalid && (lastName.dirty || lastName.touched)" class = "alert alert-danger">
<div *ngIf = "lastName.hasError('required')">
Last Name is required.
</div>
</div>
</div>
<div class = "row mb-4">
<div class = "col">
<label class = "form-label">Phone Number</label>
<input id = "phone" class = "form-control fw-bold" type = "phone" formControlName = "phone"
(change) = "saveToDataStore()">
</div>
</div>
</div>
Вот объявление формы в компоненте:
private initCheckoutForm = () => {
this.checkoutForm = this.formBuilder.group({
deliveryAddress: this.formBuilder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
phone: ['', Validators.required],
address1: ['', Validators.required],
address2: [''],
useAsBillingAddress: [''],
}),
applianceDelivery: this.formBuilder.group({
deliveryDate: ['', Validators.required],
specialInstructions: [''],
}),
paymentMethod: this.formBuilder.group({
paymentType: ['', Validators.required],
cardNumber: ['', Validators.required],
expMonth: ['', Validators.required],
expYear: ['', Validators.required],
CVV: ['', Validators.required],
defaultCreditCard: [''],
})
});
console.info('this.checkoutForm', this.checkoutForm.value);
}
🤔 А знаете ли вы, что...
Один из ключевых принципов Angular - это двунаправленное связывание данных, которое автоматически обновляет интерфейс при изменении данных и наоборот.
если у вас нет таких геттеров, как
get firstName()
{
return this.checkoutForm.get('deliveryAddress.firstName')
}
..same with the others: lastName, phone,...
Вы должны использовать это при проверке
<div *ngIf = "checkoutForm.get('deliveryAddress.firstName').invalid &&
(checkoutForm.get('deliveryAddress.firstName').dirty ||
checkoutForm.get('deliveryAddress.firstName').touched)">
ПРИМЕЧАНИЕ. Если у вас есть только уникальный валидатор, вы можете не проверять hasError('required')
Что ж, сложно создать несколько установщиков или добавить в .html эти трудно читаемые «если», так почему бы не создать директиву?
@Directive({
selector: '[formControlName],[formControl]',
exportAs: 'ngControl',
standalone: true,
})
export class ControlDirective {
constructor(@Host() @Optional() private control: NgControl) {}
get invalid() {
return this.control?.invalid;
}
get touched() {
return this.control?.touched;
}
get dirty() {
return this.control?.dirty;
}
get value() {
return this.control?.value;
}
}
Затем мы можем использовать ссылочную переменную шаблона следующим образом #variable='ngControl'
например
form = new FormGroup({
group: new FormGroup({
control: new FormControl('', Validators.required),
}),
});
и использовать
<form [formGroup] = "form">
<div formGroupName = "group">
<input #control = "ngControl" formControlName = "control" />
@if (control.invalid && control.touched) { invalid }
</div>
</form>
Обновление. Другой способ показать ошибки — просто использовать .css.
.error {
display: none;
}
.ng-invalid.ng-dirty + .error,
.ng-invalid.ng-touched + .error {
display: block;
}
Итак, мы можем написать, например.
<input [formControl] = "controlName">
<div class = "error">Required</div>