I am developing an Angular application based on PrimeNG UI library. It implements several pages which contain tables, for example UsersComponent
, AccountsComponent
, TweetsComponent
, etc.
I am using PrimeNG's Table component to display the data in table form. In order to achieve component reusability, I have created a generic TableComponent
class which implements PrimeNG table, and have added custom functionality to this table component like filters, sorting, etc.
I can pass data from UsersComponent
, AccountsComponent
, and TweetsComponent
to this TableComponent
and the data from these parent components is displayed nicely like I want.
<UsersComponent>
<TableComponent [data]="usersArray"></TableComponent>
</UsersComponent>
<AccountsComponent>
<TableComponent [data]="accountsArray"></TableComponent>
</AccountsComponent>
<TweetsComponent>
<TableComponent [data]="tweetsArray"></TableComponent>
</TweetsComponent>
However, the issue is that I want to add some methods that are specific to each component. For example, when the TableComponent
is displaying list of users, I want to be able to call methods addUser()
, deleteUser()
and updateUser()
that add, delete or update a user record, respectively. Similarly, AccountsComponent
should have its own functionality and separate, independent API calls.
How can I achieve this in Angular?
I can pass down data from parent to child component but how can I pass multiple specific methods to the child? Where will I create these methods and how shall I call them in the child component?
CodePudding user response:
From my point of view this sounds like you should implement some abstract interface (or multiple, if you want to split up logic), which will be implemented by services and then passed to the child component as an input property.
export interface CrudService<T> {
addItem(item: T): Observable<T>;
updateItem(item: T): Observable<T>;
removeItem(item: T): Observable<void>;
}
Now you can implement services specific for your use case like so:
@Injectable()
export class UserService implements CrudService<User> {
addItem(item: User): Observable<User> {
// logic specific to user
}
updateItem(item: User): Observable<User> {
// logic specific to user
}
removeItem(item: User): Observable<void> {
// logic specific to user
}
}
and pass it to your TableComponent
export class Tableomponent<T> {
@Input()
crudService: CrudService<T>;
}
Now you are able to generically call add, update or remove methods on this service. If not all entities support all CRUD operations, you should split this interface up into different interfaces.
CodePudding user response:
In your case, I would add a custom "actions" columns at the end of my array, where I would put my custom actions (and hide it if there's none).
Then, to give them the actions I want, I would use ng-content
so that I can call my component like this :
<UsersComponent>
<TableComponent [data]="usersArray">
<ng-template let-item>
<button (click)="deleteUser(item)">
<icon>delete</icon>
</button>
<ng-template>
</TableComponent>
</UsersComponent>
CodePudding user response:
I have something like this on my app (really small version to get the idea)
https://stackblitz.com/edit/angular-ivy-jj5jbt?file=src/app/hello.component.ts
I Use the table on lot of parent components but the edit, add functions are different on all the parent components, that's why i keep the functions on the parent to avoid haven lot of different function on the child component. and then pass them to the child. Also I add a parameter (id) that can be pass beetween them
export class ConfigButtons {
icon: string;
buttonText: string;
functionName: Function;
}
that's the model and then
config: ConfigButtons[] = [
{
icon: 'edit-icon',
buttonText: 'Edit User',
functionName: (userId) => this.editUser(userId),
},
];
editUser(userId: string) {
console.log('editUser', userId);
}
The full example is on the stackblitz project