I have an Angular project with two components, a generic component where the table is defined and a component from which that table is invoked by passing the required data.
The problem is that the table generates a button to delete the record, the delete function has the component itself, not the generic component.
Is it possible to call only the component table.component and then call the function?
This is the generic component, table.component.html:
<mat-table [dataSource]="dataSource" matSort >
<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
<ng-container *ngIf="column != 'actions'">
<mat-header-cell *matHeaderCellDef mat-sort-header> {{ column | titlecase }} </mat-header-cell>
<mat-cell *matCellDef="let element">{{ element[column] }}</mat-cell>
</ng-container>
<ng-container *ngIf="column == 'actions'">
<mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
<mat-cell *matCellDef="let row;let i = index" >
<button at-icon-button matTooltip="Delete" (click)="testDelete(dataSource.data[i])">
<mat-icon>delete_forever</mat-icon>
</button>
</mat-cell>
</ng-container>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
This is the table.component.ts:
@Input('dataSource') public dataSource: MatTableDataSource<any>;
@Input('displayedColumns') public displayedColumns: string[];
Child component, test1.component.html:
<app-table-edit
[dataSource]="dataSource"
[displayedColumns]="displayedColumns">
</app-table-edit>
test1.component.ts:
public dataSource: MatTableDataSource<Company>;
const company = [
{
"name":"test2Dyn",
"phoneNumber":null,
"province":null
},
{
"name":"test3Prov",
"phoneNumber":null,
"province":"Álava"
}
]
this.dataSource = new MatTableDataSource(company);
public displayedColumns: string[] = ['name','phoneNumber','province','actions']
This is the generic service from which the endPoints are invoked, api.service.ts:
constructor(
private httpClient: HttpClient,
private tConstructor: { new (m: Partial<T>, ...args: unknown[]): T },
protected apiUrl: string
) {}
public delete(id: number): Observable<void> {
return this.httpClient.delete<void>(`${this.apiUrl}/${id}`);
}
This is the child component's own service, test1.service.ts:
constructor(
private http: HttpClient
) {
super(http, Company, 'http://localhost:8080/company');
}
My problem: what is the best way to call the delete() service from the table button?
CodePudding user response:
I'm not sure I understand your question correctly, but if I do, you're looking for a simple service implementation. Please read about angular services for further info.
You have to add your generic service to the constructor in table.component.ts like this:
table.component.ts:
constructor(private genericService: GenericService) {}
then you can call the delete function of that service this way.
function testDelete(data)
{
this.genericService.delete(data.id) // note that you might access id
// differently
.subscribe(() => (console.log(this.response)));
}
here i'm logging out any responses that you migth have, but in the case of a delete you might want to show only errors. Here's a reference https://rxjs.dev/guide/subscription
CodePudding user response:
For the most generic approach, I'd suggest you to take a look at this datatable which is showcased here.
The code where the datatable is used is hosted here:
<bs-datatable #tabel [settings]="settings" [data]="artists" (reloadData)="loadArtists()">
<div *bsDatatableColumn="{ sortable: true, name: 'Name' }">
1. Artist
</div>
<div *bsDatatableColumn="{ sortable: true, name: 'YearStarted' }">
2. Year started
</div>
<div *bsDatatableColumn="{ sortable: true, name: 'YearQuit' }">
3. Year quit
</div>
<ng-template bsRowTemplate let-artist>
<tr>
<td >{{ artist.name }}</td>
<td >{{ artist.yearStarted }}</td>
<td >{{ artist.yearQuit }}</td>
<td >
<button (click)="doSomething()">Delete</button>
</td>
</tr>
</ng-template>
</bs-datatable>
Note that:
*bsDatatableColumn
is the same as<ng-template bsDatatableColumn><div>...</div></ng-template>
. This sets the template on theBsDatatableComponent
.<ng-template bsRowTemplate let-artist>
can also be written as<tr *bsRowTemplate="{ artist: $implicit }">
The BsRowTemplateDirective
takes in the BsDatatableComponent
and TemplateRef
(it's annotated by a *
as explained above), and simply sets the templateRef of the BsDatatableComponent
@Directive({ selector: '[bsRowTemplate]' })
export class BsRowTemplateDirective {
constructor(private datatableComponent: BsDatatableComponent, templateRef: TemplateRef<any>) {
this.datatableComponent.rowTemplate = templateRef;
}
}
However, I fear that refactoring your code snippet to move the rowTemplate to the consuming component will not be a walk in the park.