Как реализовать проверку ввода реактивной формы Angular

Вот моя форма ниже: Текущие проверки ошибок в форме не работают.

<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 - это двунаправленное связывание данных, которое автоматически обновляет интерфейс при изменении данных и наоборот.


65
1

Ответ:

Решено

если у вас нет таких геттеров, как

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>