title: Problem with Angular 6 Validator for form in table Angular Material
body: <p>I'm building an app with Angular 6 and I have a problem with reactive forms.I'm learning Angular. I have a form for all the rows of a table with one input to validate, which is PRODUCT_QUANTITY. When the number input changes, it submits the form to update the table with the new value. The problem is when I focus on the element and I don't change the value, the validator error is activated for all the rows of the table. I want this activation only for the row concerned when the quantity is not set. Sorry if my code isn't perfect.
  Could you help me to solve this problem? Thank you</p>
  
  <p>Here's the code :</p>
  
  <p><strong>tables.component.html</strong></p>
  
  <pre><code>&lt;mat-form-field&gt;
      &lt;input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter"&gt;
  &lt;/mat-form-field&gt;
  &lt;ng-container&gt;
      &lt;mat-form-field&gt;
          &lt;mat-select placeholder="Filter par type de produit"
                      multiple (selectionChange)="displayData($event.value)"
                      [(ngModel)]="selectedProductsId"
                      #productIdSelect="ngModel"&gt;
              &lt;button
                      mat-raised-button
                      class="mat-warn fill text-sm"
                      (click)="emptyFilter(productIdSelect,ids)"&gt;
                  Supprimer filtre
              &lt;/button&gt;
              &lt;mat-option *ngFor="let product of productListType" [value]="product.PRODUCTS_id"&gt;{{product.PRODUCTS_title}}&lt;/mat-option&gt;
          &lt;/mat-select&gt;
      &lt;/mat-form-field&gt;
  &lt;/ng-container&gt;
  &lt;div class="mat-elevation-z8"&gt;
      &lt;form [formGroup]="form" (submit)="addProductToList()"&gt;
          &lt;table mat-table [dataSource]="dataSource" matSort&gt;
  
  
              &lt;ng-container matColumnDef="PRODUCT_name"&gt;
                  &lt;th mat-header-cell *matHeaderCellDef mat-sort-header&gt; Nom du produit&lt;/th&gt;
                  &lt;td mat-cell *matCellDef="let row"&gt; {{row.PRODUCT_name}} &lt;/td&gt;
              &lt;/ng-container&gt;
  
              &lt;ng-container matColumnDef="PRODUIT_TYPE"&gt;
                  &lt;th mat-header-cell *matHeaderCellDef mat-sort-header&gt; Type de produit&lt;/th&gt;
                  &lt;td mat-cell *matCellDef="let row"&gt; {{row.PRODUIT_TYPE}}&lt;/td&gt;
              &lt;/ng-container&gt;
  
              &lt;ng-container matColumnDef="PRODUCT_QUANTITY"&gt;
                  &lt;th mat-header-cell *matHeaderCellDef mat-sort-header&gt; Quantité&lt;/th&gt;
                  &lt;td mat-cell *matCellDef="let row"&gt;
                      &lt;mat-form-field style="width: 50%"&gt;
                          &lt;input (change)="setIdProduct(row.PRODUCT_id)" formControlName="quantity" matInput min="0" type="number" placeholder="Quantité" value="{{row.PRODUCT_QUANTITY}}"&gt;
                      &lt;/mat-form-field&gt;
                  &lt;/td&gt;
              &lt;/ng-container&gt;
  
              &lt;ng-container matColumnDef="PRODUCT_COMMENT"&gt;
                  &lt;th mat-header-cell *matHeaderCellDef mat-sort-header&gt;Commentaire&lt;/th&gt;
                  &lt;td mat-cell *matCellDef="let row"&gt;
                      &lt;mat-form-field style="width: 60%"&gt;
                          &lt;textarea (change)="setIdProduct(row.PRODUCT_id)" formControlName="remark" matInput placeholder="Ajouter un commentaire"
                                    value="{{row.PRODUCT_COMMENT}}"&gt;&lt;/textarea&gt;
                      &lt;/mat-form-field&gt;
                  &lt;/td&gt;
              &lt;/ng-container&gt;
  
              &lt;ng-container matColumnDef="VALIDATE"&gt;
                  &lt;th style="display: none" mat-header-cell *matHeaderCellDef mat-sort-header&gt;Ajouter un produit&lt;/th&gt;
                  &lt;td mat-cell *matCellDef="let row"&gt;
                      &lt;button id="submitForProduct" style="display: none;" mat-raised-button color="primary" type="submit"&gt;Ajouter à ma liste de
                          course
                      &lt;/button&gt;
                  &lt;/td&gt;
              &lt;/ng-container&gt;
  
              &lt;tr mat-header-row *matHeaderRowDef="displayedColumns"&gt;&lt;/tr&gt;
              &lt;tr mat-row *matRowDef="let row; columns: displayedColumns;"&gt;&lt;/tr&gt;
          &lt;/table&gt;
  
      &lt;/form&gt;
  
      &lt;mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 100]"&gt;&lt;/mat-paginator&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>tables.component.ts</strong></p>
  
  <pre><code>import {Component, OnInit, ViewChild} from '@angular/core';
  import {MatPaginator, MatSnackBar, MatSort, MatTableDataSource} from '@angular/material';
  import {ProductService} from '../../services/product.service';
  import {Product} from '../../models/product';
  import {ProductType} from '../../models/producttype';
  import {FormBuilder, FormGroup, NgModel, Validators} from '@angular/forms';
  import {Subscription} from 'rxjs';
  import {forEach} from 'async';
  
  @Component({
      selector: 'app-tables',
      templateUrl: './tables.component.html',
      styleUrls: ['./tables.component.scss']
  })
  export class TablesComponent implements OnInit {
      displayedColumns = ['PRODUCT_name', 'PRODUIT_TYPE', 'PRODUCT_QUANTITY', 'PRODUCT_COMMENT', 'VALIDATE'];
      dataSource: MatTableDataSource&lt;Product&gt;;
      productListType: ProductType[];
      productListItem: Product[] = [];
      filteredArray: Product[] = [];
      selectedProductsId: ProductType[];
      ids: any[] = [];
      form: FormGroup;
      response: Subscription;
      idProduct: number;
  
  
      @ViewChild(MatPaginator) paginator: MatPaginator;
      @ViewChild(MatSort) sort: MatSort;
  
      constructor(private productProvider: ProductService, private addProduct: FormBuilder, private snackBar: MatSnackBar) {
          console.log(this.productListItem);
      }
  
      ngOnInit() {
          this.productProvider.getAllProducts().subscribe(
              r =&gt; {
                  this.productListType = r['products'] as ProductType[];
                  this.productListType.forEach(product =&gt; {
                      this.ids.push(product.PRODUCTS_id);
                      product.PRODUCTS_products.forEach(productItem =&gt; {
                          this.productListItem.push(new Product(
                              productItem.PRODUCT_id,
                              productItem.PRODUCT_name,
                              productItem.PRODUCT_unit,
                              product.PRODUCTS_title,
                              product.PRODUCTS_id,
                              0,
                              ''));
                      });
                  });
                  this.productProvider.getProductsHousehold(1).subscribe(
                      result =&gt; {
                          this.productListItem.map(productItem =&gt; {
                              result.products.map(productItemR =&gt; {
                                  if (productItemR.PRODUCTS_LIST_id_prod === productItem.PRODUCT_id) {
                                      console.log(productItemR.PRODUCTS_LIST_QUANTITY);
                                      productItem.PRODUCT_QUANTITY = productItemR.PRODUCTS_LIST_quantity;
                                      productItem.PRODUCT_COMMENT = productItemR.PRODUCTS_LIST_remark;
                                  }
                              });
                          });
                          console.log(this.productListItem)
                      });
                  this.dataSource = new MatTableDataSource&lt;Product&gt;(this.productListItem);
                  this.dataSource.sort = this.sort;
                  this.dataSource.paginator = this.paginator;
              });
          this.form = this.addProduct.group({
              quantity: ['', [Validators.required]],
              remark: ['']
          });
      }
  
  // filter the list of products
      applyFilter(filterValue: string) {
          filterValue = filterValue.trim(); // Remove whitespace
          filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
          this.dataSource.filter = filterValue;
          if (this.dataSource.paginator) {
              this.dataSource.paginator.firstPage();
          }
      }
  
  //Display data when filter changed    
      displayData(event) {
          let array: any;
          array = event;
          if (array.length === 0) {
              array = this.ids;
          }
          console.log(array);
          this.filteredArray = [];
          this.productListType.forEach(product =&gt; {
              array.forEach(productId =&gt; {
                  if (product.PRODUCTS_id === productId) {
                      product.PRODUCTS_products.forEach(pro =&gt; {
                          this.filteredArray.push(new Product(
                              pro.PRODUCT_id,
                              pro.PRODUCT_name,
                              pro.PRODUCT_unit,
                              product.PRODUCTS_title,
                              product.PRODUCTS_id,
                              pro.PRODUCT_QUANTITY,
                              pro.PRODUCT_COMMENT));
                      });
                  }
              });
          });
          this.dataSource = new MatTableDataSource&lt;Product&gt;(this.filteredArray);
          this.dataSource.sort = this.sort;
          this.dataSource.paginator = this.paginator;
      }
  //empty the filter
      emptyFilter(select
                      :
                      NgModel, values
      ) {
          select.update.emit([]);
          this.displayData([]);
      }
  
  //set Id Product and trigger event submit
      setIdProduct(PRODUCT_id
                       :
                       number
      ) {
          this.idProduct = PRODUCT_id;
          console.log(this.idProduct);
          document.getElementById('submitForProduct').click();
      }
  
  // function called when the form is submitted    
      addProductToList() {
          if (this.form.invalid || this.idProduct &lt; 0) {
              this.snackBar.open('Veuillez renseigner tous les champs', '', {
                  duration: 2000
              });
              return;
          }
          const quantity = this.form.controls.quantity.value;
          const remark = this.form.controls.remark.value;
          this.response = this.productProvider.addProductToList(this.idProduct, 1, quantity, remark).subscribe(
              result =&gt; {
                  if (result === true) {
                      this.snackBar.open('Le produit a bien été ajouté à la liste', '', {
                          duration: 2000
                      });
                  } else {
                      this.snackBar.open('Produit non ajouté à la liste', '', {
                          duration: 2000
                      });
                  }
              });
      }
  }
  </code></pre>