2

The problem is that after filling the field, there are mat-errors that input is required even though they are entered. Without "

if (this.addInvoiceForm.invalid) {return;"

Everything works fine

Here's my HTML: `

<form method="POST" [formGroup]="addInvoiceForm" (ngSubmit)="addData()">
  <div class="formularz" *ngFor="let item of items">
    <mat-form-field >
      <mat-label>Name</mat-label>
      <input type="text" matInput formControlName="name"  [formControl]="item.nameFormControl" maxlength="30" minlength="3">
      <mat-error *ngIf="addInvoiceF['name'].errors && addInvoiceF['name'].errors['required']">Name is required</mat-error>
    </mat-form-field>
    <mat-form-field>
      <mat-label>Count</mat-label>
      <input type="number"  formControlName="count" matInput [formControl]="item.countFormControl" maxlength="100" minlength="1">
    </mat-form-field>
    <mat-form-field >
      <mat-label>Price</mat-label>
      <input type="number" matInput formControlName="price"  [formControl]="item.priceFormControl" maxlength="1000000" minlength="1">
      <mat-error *ngIf="addInvoiceF['price'].errors && addInvoiceF['price'].errors['required']">Price is required</mat-error>
    </mat-form-field>
    <button mat-icon-button color="primary" class="delete" matTooltip="Remove item" (click)="deleteForm(item)">
      <mat-icon>delete</mat-icon>
    </button>
  </div>
  <div class="add-new">
    <button type="button" mat-icon-button color="primary" class="add" matTooltip="Add new item" (click)="addForm()">
      <mat-icon>add</mat-icon>
      Add new item
    </button>
  </div>
  <div class="add">
    <button mat-icon-button color="primary" class="myButton" id="add_data_button">
      Submit
    </button>
  </div>
</form>

` And typescript:

    import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder, FormGroup } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
import { ViewChild, ElementRef } from '@angular/core';
import { PagesService } from '../pages.service';
import { Router } from '@angular/router';

@Component({
  selector: 'app-new-invoice',
  templateUrl: './new-invoice.component.html',
  styleUrls: ['./new-invoice.component.css']
})
export class NewInvoiceComponent implements OnInit {


  matcher = new ErrorStateMatcher();
  addInvoiceForm!: FormGroup;
  get addInvoiceF() { return this.addInvoiceForm.controls; }

  items: any[] = [
    { nameFormControl: new FormControl(), countFormControl: new FormControl(), priceFormControl: new FormControl() }
  ];

  formRows: any[] = [{ name: '', count: 1, price: '' }];

  constructor(
    private formBuilder: FormBuilder,
    private pagesService: PagesService,
    private router: Router
  ) {
    window.addEventListener('beforeunload', () => {
      for (let key in localStorage) {
        if (key.includes('formRows')) {
          localStorage.removeItem(key);
        }
      }
    });
  }


  ngOnInit(): void {
    this.addInvoiceForm = this.formBuilder.group({
      name: ['', Validators.required],
      count: [''],
      price: ['', Validators.required],
    });
  }

  addFormRow() {
    this.formRows.push({ name: '', count: 1, price: '' });
  }

  addForm() {
    this.items.push({ nameFormControl: new FormControl(), priceFormControl: new FormControl() });
  }

  deleteForm(item: any) {
    const index = this.items.indexOf(item);
    if (index !== -1) {
      this.items.splice(index, 1);
    }
  }

  addData() {
    if (this.addInvoiceForm.invalid) {
      return;
    }
    this.formRows = this.items.map(item => ({
      name: item.nameFormControl.value || '',
      count: item.countFormControl ? item.countFormControl.value : '',
      price: item.priceFormControl.value || '' 
    }));
    this.pagesService.setFormData(this.formRows);
    console.log(this.formRows);
    this.router.navigate(['/preview-invoice']);
  }
}

I also tried with else:

     addData() {
    if (this.addInvoiceForm.invalid) {
      return;
    } else {
    this.formRows = this.items.map(item => ({
      name: item.nameFormControl.value || '',
      count: item.countFormControl ? item.countFormControl.value : '',
      price: item.priceFormControl.value || '' 
    }));
    this.pagesService.setFormData(this.formRows);
    console.log(this.formRows);
    this.router.navigate(['/preview-invoice']);
  }}
}

And still the same problem. So there's no problem with service or data it doesn't work because of "this.addInvoiceForm.invalid" and I don't know why.

  • 1
    I think your issue comes from the fact you are using `formControlName` and `[formControl]` at the same time, you should either use one or the other, not both. https://stackoverflow.com/a/40172009/8404545 – Max Apr 25 '23 at 12:19

1 Answers1

0

use updateValueAndValidity() method before checking the form is valid.

addData() {
      this.addInvoiceForm?.updateValueAndValidity();
      this.addInvoiceForm?.get('name')?.updateValueAndValidity();
      this.addInvoiceForm?.get('price')?.updateValueAndValidity();
      if (this.addInvoiceForm.invalid) {
          return;
      }
.....
Deepu Reghunath
  • 8,132
  • 2
  • 38
  • 47