Add selection functionality to product list with delete option
This commit is contained in:
@@ -11,10 +11,12 @@ import {MatFormField, MatLabel} from '@angular/material/form-field';
|
||||
import {MatInput} from '@angular/material/input';
|
||||
import {MatButton, MatIconButton} from '@angular/material/button';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {FormBuilder, ReactiveFormsModule} from '@angular/forms';
|
||||
import {FormBuilder, ReactiveFormsModule, FormsModule} from '@angular/forms';
|
||||
import {MatDialog, MatDialogModule} from '@angular/material/dialog';
|
||||
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
|
||||
import {forkJoin, finalize} from 'rxjs';
|
||||
import {SelectionModel} from '@angular/cdk/collections';
|
||||
import {MatCheckboxModule} from '@angular/material/checkbox';
|
||||
|
||||
import {PsItem} from '../../interfaces/ps-item';
|
||||
import {ProductListItem} from '../../interfaces/product-list-item';
|
||||
@@ -27,14 +29,15 @@ import {ProductDialogData, PsProductDialogComponent} from '../ps-product-dialog/
|
||||
templateUrl: './ps-product-crud.component.html',
|
||||
styleUrls: ['./ps-product-crud.component.css'],
|
||||
imports: [
|
||||
CommonModule, ReactiveFormsModule,
|
||||
CommonModule, ReactiveFormsModule, FormsModule,
|
||||
MatTable, MatColumnDef, MatHeaderRow, MatHeaderRowDef, MatRow, MatRowDef,
|
||||
MatHeaderCell, MatHeaderCellDef, MatCell, MatCellDef, MatNoDataRow,
|
||||
MatSortModule, MatPaginatorModule,
|
||||
MatFormField, MatLabel, MatInput,
|
||||
MatButton, MatIconButton, MatIcon,
|
||||
MatDialogModule,
|
||||
MatProgressSpinnerModule
|
||||
MatProgressSpinnerModule,
|
||||
MatCheckboxModule
|
||||
]
|
||||
})
|
||||
export class PsProductCrudComponent implements OnInit {
|
||||
@@ -50,12 +53,16 @@ export class PsProductCrudComponent implements OnInit {
|
||||
private manMap = new Map<number, string>();
|
||||
private supMap = new Map<number, string>();
|
||||
|
||||
displayed: string[] = ['id', 'name', 'category', 'manufacturer', 'supplier', 'priceTtc', 'quantity', 'actions'];
|
||||
// added 'select' column first
|
||||
displayed: string[] = ['select', 'id', 'name', 'category', 'manufacturer', 'supplier', 'priceTtc', 'quantity', 'actions'];
|
||||
dataSource = new MatTableDataSource<any>([]);
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
@ViewChild(MatSort) sort!: MatSort;
|
||||
@ViewChild(MatTable) table!: MatTable<any>;
|
||||
|
||||
// selection model (multiple)
|
||||
selection = new SelectionModel<any>(true, []);
|
||||
|
||||
filterCtrl = this.fb.control<string>('');
|
||||
|
||||
isLoading = false;
|
||||
@@ -121,6 +128,8 @@ export class PsProductCrudComponent implements OnInit {
|
||||
|
||||
private bindProducts(p: (ProductListItem & { priceHt?: number })[]) {
|
||||
const vat = 0.2;
|
||||
// clear selection because objects will be new after reload
|
||||
this.selection.clear();
|
||||
this.dataSource.data = p.map(x => ({
|
||||
...x,
|
||||
categoryName: x.id_category_default ? (this.catMap.get(x.id_category_default) ?? '') : '',
|
||||
@@ -203,4 +212,55 @@ export class PsProductCrudComponent implements OnInit {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- Selection helpers ---
|
||||
|
||||
private getVisibleRows(): any[] {
|
||||
const data = this.dataSource.filteredData || [];
|
||||
if (!this.paginator) return data;
|
||||
const start = this.paginator.pageIndex * this.paginator.pageSize;
|
||||
return data.slice(start, start + this.paginator.pageSize);
|
||||
}
|
||||
|
||||
isAllSelected(): boolean {
|
||||
const visible = this.getVisibleRows();
|
||||
return visible.length > 0 && visible.every(r => this.selection.isSelected(r));
|
||||
}
|
||||
|
||||
isAnySelected(): boolean {
|
||||
return this.selection.hasValue();
|
||||
}
|
||||
|
||||
masterToggle(checked: boolean) {
|
||||
const visible = this.getVisibleRows();
|
||||
if (checked) {
|
||||
visible.forEach(r => this.selection.select(r));
|
||||
} else {
|
||||
visible.forEach(r => this.selection.deselect(r));
|
||||
}
|
||||
}
|
||||
|
||||
toggleSelection(row: any, checked: boolean) {
|
||||
if (checked) this.selection.select(row);
|
||||
else this.selection.deselect(row);
|
||||
}
|
||||
|
||||
deleteSelected() {
|
||||
if (this.isLoading) return;
|
||||
const ids = this.selection.selected.map(s => s.id);
|
||||
if (!ids.length) return;
|
||||
if (!confirm(`Supprimer ${ids.length} produit(s) sélectionné(s) ?`)) return;
|
||||
|
||||
this.isLoading = true;
|
||||
const calls = ids.map((id: number) => this.ps.deleteProduct(id));
|
||||
forkJoin(calls).pipe(finalize(() => {
|
||||
// nothing extra, reload will clear selection
|
||||
})).subscribe({
|
||||
next: () => this.reload(),
|
||||
error: (e: unknown) => {
|
||||
this.isLoading = false;
|
||||
alert('Erreur: ' + (e instanceof Error ? e.message : String(e)));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user