Почему правила валидаторов, похоже, не работают при использовании этого примера реактивной формы в моем проекте Angular?

#angular #primeng #angular-reactive-forms

#angular #primeng #angular-reactive-forms

Вопрос:

Я работаю над проектом Angular с использованием реактивной формы, и у меня есть следующие сомнения относительно стратегии проверки формы. Я попытаюсь подробно объяснить, что я сделал и в чем моя проблема.

В свой компонентный HTML-код я поместил эту форму (которая использует компоненты PrimeNG):

 <form [formGroup]="projectForm">
    <p-accordion [multiple]="true">
      <p-accordionTab header="Informazioni generali ordine">
        <div id="informazioni_generale_ordine">
          <div class="row">
            <div class="col-2">
              <p>ID Ordine</p>
            </div>
            <div class="col-10">
              <p-inputNumber id="idOrdine" formControlName="idOrdine"></p-inputNumber>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Data inserimento ordine</p>
            </div>
            <div class="col-10">
              <p-calendar id="dataInserimentoOrdine" formControlName="dataInserimentoOrdine"></p-calendar>
            </div>
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Stato ordine</p>
          </div>
          <div class="col-10">
            <input id="statoOrdine" formControlName="statoOrdine" type="text" pInputText />
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Commessa</p>
          </div>
          <div class="col-10">
            <input id="commessa" formControlName="commessa" type="text" pInputText />
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>CIG</p>
          </div>
          <div class="col-10">
            <input id="CIG" formControlName="CIG" type="text" pInputText />
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Data inizio attività</p>
          </div>
          <div class="col-10">
            <p-calendar id="dataInizioAttivita" formControlName="dataInizioAttivita"></p-calendar>
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Data fine attività</p>
          </div>
          <div class="col-10">
            <p-calendar id="dataFineAttivita" formControlName="dataFineAttivita"></p-calendar>
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Referente</p>
          </div>
          <div class="col-10">
            <input id="referente" formControlName="referente" type="text" pInputText />
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Ruolo referente</p>
          </div>
          <div class="col-10">
            <input id="ruoloReferente" formControlName="ruoloReferente" type="text" pInputText />
          </div>
        </div>

        <div class="row">
          <div class="col-2">
            <p>Tipologia di partecipazione</p>
          </div>
          <div class="col-10">
            <input id="tipologiaDiPartecipazione" formControlName="tipologiaDiPartecipazione" type="text" pInputText />
          </div>
        </div>


        <div class="row">
          <div class="col-2">
            <p>Quota percentuale di RTI</p>
          </div>
          <div class="col-10">
            <p-inputNumber id="quotaPercentualeDiRTI" formControlName="quotaPercentualeDiRTI"  suffix="%"></p-inputNumber>
          </div>
        </div>


      </p-accordionTab>
      <p-accordionTab header="Informazioni cliente">
        <div id="informazioni_cliente">

          <div class="row">
            <div class="col-2">
              <p>Cliente</p>
            </div>
            <div class="col-10">
              <input id="cliente" formControlName="cliente" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Partita IVA cliente</p>
            </div>
            <div class="col-10">
              <input id="vatCliente" formControlName="vatCliente" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Cliente finale</p>
            </div>
            <div class="col-10">
              <input id="clienteFinale" formControlName="clienteFinale" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Partita IVA cliente finale</p>
            </div>
            <div class="col-10">
              <input id="vatClienteFinale" formControlName="vatClienteFinale" type="text" pInputText />
            </div>
          </div>

        </div>
      </p-accordionTab>

      <p-accordionTab header="Informazioni contratto">
        <div id="informazioni_contratto">
          <div class="row">
            <div class="col-2">
              <p>Tipologia contratto</p>
            </div>
            <div class="col-10">
              <input id="tipologiaContratto" formControlName="tipologiaContratto" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Importo contratto</p>
            </div>
            <div class="col-10">
              <p-inputNumber id="importoContratto" formControlName="importoContratto"  mode="currency" currency="EUR" locale="de-DE"></p-inputNumber>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Link Contratto</p>
            </div>
            <div class="col-10">
              <input id="linkContratto" formControlName="linkContratto" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Data sottoscrizione contratto</p>
            </div>
            <div class="col-10">
              <p-calendar id="dataSottoscrizioneContratto" formControlName="dataSottoscrizioneContratto"></p-calendar>
            </div>
          </div>
        </div>
      </p-accordionTab>

      <p-accordionTab header="Informazioni società">
        <div id="informazioni_societa">
          <div class="row">
            <div class="col-2">
              <p>Nome Società</p>
            </div>
            <div class="col-10">
              <input id="nomeSocieta" formControlName="nomeSocieta" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Partita IVA Società</p>
            </div>
            <div class="col-10">
              <input id="vatSocieta" formControlName="vatSocieta" type="text" pInputText/>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>BU</p>
            </div>
            <div class="col-10">
              <input id="bu" formControlName="bu" type="text" pInputText />
            </div>
          </div>
        </div>
      </p-accordionTab>

      <p-accordionTab header="Informazioni accordo quadro">
        <div id="informazioni_accordo_quadro">
          <div class="row">
            <div class="col-2">
              <p>Presenza accordo quadro</p>
            </div>
            <div class="col-10">
              <p-selectButton [options]="presenzaAQOption" id="presenzaAQ" formControlName="presenzaAQ" ></p-selectButton>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Link identificatovo accordo quadro</p>
            </div>
            <div class="col-10">
              <input id="linkIdentificativoAQ" formControlName="linkIdentificativoAQ" type="text" pInputText />
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Accordo quadro</p>
            </div>
            <div class="col-10">
              <p-inputNumber id="accordoQaudro" formControlName="accordoQaudro" mode="currency" currency="EUR" locale="de-DE" ></p-inputNumber>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Residuo accordo quadro</p>
            </div>
            <div class="col-10">
              <p-inputNumber  id="residuoAccordoQaudro" formControlName="residuoAccordoQaudro" mode="currency" currency="EUR" locale="de-DE"></p-inputNumber>
            </div>
          </div>

          <div class="row">
            <div class="col-2">
              <p>Compagine di accordo quadro</p>
            </div>
            <div class="col-10">
              <input id="compagineDiAQ" formControlName="compagineDiAQ" type="text" pInputText />
            </div>
          </div>


        </div>
    </p-accordionTab>
    </p-accordion>
</form>
  

Визуализация чего-то вроде этого:

введите описание изображения здесь

Как вы можете видеть на предыдущем изображении и фрагменте кода, поскольку у меня много полей, я разделил эти поля на элементы аккордеона (но это не должно быть проблемой).

Затем в моем компонентном классе TypeScript я объявил это поле FormGroup (которое я ввел в свой конструктор):

 projectForm: FormGroup;
  

Затем в компонентном методе ngOnInit() я определил все поля, определенные в HTML-форме, для извлечения значений, вставленных пользователем в поля ввода формы:

 ngOnInit() {

  this.projectForm = this.fb.group({
  idOrdine: [null, [Validators.required, Validators.minLength(5)]],
  dataInserimentoOrdine: [null, [Validators.required, Validators.minLength(5)]],
  statoOrdine: [null, [Validators.required, Validators.minLength(5)]],
  commessa: [null, [Validators.required, Validators.minLength(5)]],
  CIG: [null, [Validators.required, Validators.minLength(5)]],
  dataInizioAttivita: [null, [Validators.required, Validators.minLength(5)]],
  dataFineAttivita: [null, [Validators.required, Validators.minLength(5)]],
  referente: [null, [Validators.required, Validators.minLength(5)]],
  ruoloReferente: [null, [Validators.required, Validators.minLength(5)]],
  tipologiaDiPartecipazione: [null, [Validators.required, Validators.minLength(5)]],
  quotaPercentualeDiRTI: [null, [Validators.required, Validators.minLength(5)]],

  cliente: [null, [Validators.required, Validators.minLength(5)]],
  vatCliente: [null, [Validators.required, Validators.minLength(5)]],
  clienteFinale: [null, [Validators.required, Validators.minLength(5)]],
  vatClienteFinale: [null, [Validators.required, Validators.minLength(5)]],

  tipologiaContratto: [null, [Validators.required, Validators.minLength(5)]],
  importoContratto: [null, [Validators.required, Validators.minLength(5)]],
  linkContratto: [null, [Validators.required, Validators.minLength(5)]],
  dataSottoscrizioneContratto: [null, [Validators.required, Validators.minLength(5)]],

  nomeSocieta: [null, [Validators.required, Validators.minLength(5)]],
  vatSocieta: [null, [Validators.required, Validators.minLength(5)]],
  bu: [null, [Validators.required, Validators.minLength(5)]],

  presenzaAQ: [null, [Validators.required, Validators.minLength(5)]],
  linkIdentificativoAQ: [null, [Validators.required, Validators.minLength(5)]],
  accordoQaudro: [null, [Validators.required, Validators.minLength(5)]],
  residuoAccordoQaudro: [null, [Validators.required, Validators.minLength(5)]],
  compagineDiAQ: [null, [Validators.required, Validators.minLength(5)]]

});
  

Наконец, в моем HTML я определил кнопку с событием для извлечения значений, вставленных пользователем в мою форму, что-то вроде этого:

 <button pButton type="button" label="Save" icon="pi pi-check" (click)="saveOrder($event)"></button>
  

на данный момент метод SaveOrder() выводит только значения скомпилированной формы:

 public saveOrder(event) {
    console.log("saveOrder() START");
    console.log(this.projectForm.value);
}
  

Кажется, это работает: при нажатии кнопки Сохранить вызывается метод SaveOrder(), и я вижу, что поле this.projectForm.value содержит значения, вставленные пользователем в форму …. до сих пор кажется, что все в порядке…

Проблема связана с ролями проверки. Как вы можете видеть на данный момент, я вставил те же поддельные правила, чтобы протестировать его (затем я создам специальную проверку для всех моих полей):

 [Validators.required, Validators.minLength(5)]
  

в основном все поля запрашиваются и должны иметь длину не менее 5 символов. Итак, я ожидал, что если я не скомпилирую определенное поле или если я вставлю значение, состоящее из символа <5, это приведет к ошибке…но это не так.

Фактически, например, если пользователь не вставляет никаких значений в мою форму и не отправляет эту форму, я не получаю ошибки. Просто метод SaveOrder() выведет в консоль объект, где все поля пусты.

Почему? Что не так? Чего мне не хватает? Как я могу исправить эту проблему?

Ответ №1:

Angular выполняет несколько действий в фоновом режиме при использовании ReactiveForms.

Пока все поля не станут действительными, this.form.valid будет false . Это всегда первое, что нужно проверить при отправке формы. Если это значение равно false, не продолжайте ничего сохранять. Если вы добавите [disabled]=»!form.valid» к кнопке, она останется отключенной, пока не пройдут все проверки.

Ничего не заполняя в форме, просто откройте инспектор элементов и выберите элемент управления, в который вы добавили проверки. Вы должны увидеть, что он добавил ng-invalid в атрибут class. Вы можете использовать это, чтобы выделить поля ошибок с помощью CSS.

Например:

  .ng-invalid { border: 1px solid red }
  

Основой этого метода является то, что он будет показывать ошибку, даже когда пользователь просто попадает на страницу.

Поэтому обычно вместе с ним используется другой класс, с ng-касанием.

 .ng-touched.ng-invalid { ... }
  

Проблема в том, что ng-touched будет привязан только при посещении поля хотя бы один раз. Чтобы иметь возможность использовать это, вы можете использовать цикл, чтобы пройти через все элементы управления и коснуться их программно.

Также можно отобразить сообщение об ошибке, используя ngIf, которое будет отображаться только при наличии ошибки.

Например:

 <ng-container *ngIf="form.controls.get('idOrdine').errors">Error message</ng-container>
  

Предпочтительно это следует использовать с переменной, которая устанавливается только при отправке формы, чтобы ошибки не появлялись при загрузке страницы в первый раз.

Вы можете взглянуть на элементы управления, а также заглянуть в экземпляр формы при отправке, чтобы получить более четкое представление о том, что происходит внутри формы. Вы можете найти множество способов сделать то же самое, но решения могут определяться только тем, какое поведение точно требуется.

Ответ №2:

Я столкнулся с той же проблемой. Я исправил это с помощью

 ngNativeValidate
  

Используйте его, как показано ниже:-

 <form ngNativeValidate [formGroup]="form" (ngSubmit)="onSubmit()">
  

Ответ №3:

Это ожидаемое поведение форма по-прежнему недействительна, пока не будет соответствовать определенным критериям проверки, все, что вам нужно, это добавить свою пользовательскую логику и отобразить правильное сообщение об ошибке в шаблоне и запретить вызов API, пока форма не станет действительной.

 public saveOrder() {
  // if form is invalid do not do any action.
  if (this.projectForm.invalid) {
     return
  }

 // call api or whatever your logic once form is submitted with valid data.
}
  

Если вы напечатаете, console.log(this.projectForm.controls) вы увидите все элементы управления с их свойствами, вы сможете заметить статус каждого элемента управления формы, т.е. valid , touched pristine подробнее dirty читайте.

И на основе каждого статуса управления формой вы можете показать соответствующую ошибку в шаблоне.