Я создаю приложение с Angular 6, и у меня проблема с реактивными формами. Я изучаю Angular.У меня есть форма для всех строк таблицы с одним входом для проверки, который является PRODUCT_QUANTITY.Когда ввод числа изменяется, он отправляет форму для обновления таблицы новым значением.Проблема в том, что когда я фокусируюсь на элементе и не меняю значение, ошибка валидатора активируется для всех строк таблицы.Я хочу эту активацию только для соответствующей строки, когда количество не установлено.Извините, если мой код не идеален.Не могли бы вы помочь мне решить эту проблему?Спасибо
Вот код:
tables.component.html
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
<ng-container>
<mat-form-field>
<mat-select placeholder="Filter par type de produit"
multiple (selectionChange)="displayData($event.value)"
[(ngModel)]="selectedProductsId"
#productIdSelect="ngModel">
<button
mat-raised-button
class="mat-warn fill text-sm"
(click)="emptyFilter(productIdSelect,ids)">
Supprimer filtre
</button>
<mat-option *ngFor="let product of productListType" [value]="product.PRODUCTS_id">{{product.PRODUCTS_title}}</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<div class="mat-elevation-z8">
<form [formGroup]="form" (submit)="addProductToList()">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="PRODUCT_name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Nom du produit</th>
<td mat-cell *matCellDef="let row"> {{row.PRODUCT_name}} </td>
</ng-container>
<ng-container matColumnDef="PRODUIT_TYPE">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Type de produit</th>
<td mat-cell *matCellDef="let row"> {{row.PRODUIT_TYPE}}</td>
</ng-container>
<ng-container matColumnDef="PRODUCT_QUANTITY">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Quantité</th>
<td mat-cell *matCellDef="let row">
<mat-form-field style="width: 50%">
<input (change)="setIdProduct(row.PRODUCT_id)" formControlName="quantity" matInput min="0" type="number" placeholder="Quantité" value="{{row.PRODUCT_QUANTITY}}">
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="PRODUCT_COMMENT">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Commentaire</th>
<td mat-cell *matCellDef="let row">
<mat-form-field style="width: 60%">
<textarea (change)="setIdProduct(row.PRODUCT_id)" formControlName="remark" matInput placeholder="Ajouter un commentaire"
value="{{row.PRODUCT_COMMENT}}"></textarea>
</mat-form-field>
</td>
</ng-container>
<ng-container matColumnDef="VALIDATE">
<th style="display: none" mat-header-cell *matHeaderCellDef mat-sort-header>Ajouter un produit</th>
<td mat-cell *matCellDef="let row">
<button id="submitForProduct" style="display: none;" mat-raised-button color="primary" type="submit">Ajouter à ma liste de
course
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</form>
<mat-paginator [pageSize]="10" [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
</div>
tables.component.ts
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<Product>;
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 => {
this.productListType = r['products'] as ProductType[];
this.productListType.forEach(product => {
this.ids.push(product.PRODUCTS_id);
product.PRODUCTS_products.forEach(productItem => {
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 => {
this.productListItem.map(productItem => {
result.products.map(productItemR => {
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<Product>(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 => {
array.forEach(productId => {
if (product.PRODUCTS_id === productId) {
product.PRODUCTS_products.forEach(pro => {
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<Product>(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 < 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 => {
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
});
}
});
}
}