Reputation: 21
I have two components parent-component, lookup-table-component (child component, intended to be reused by multiple parents)|
lookup-table has a dataSource setup (for AG grid) which is supposed to call getRowData using a function of parent
getPageData(params)
As I am supposed to use this function in child
I am using the following approach.
Parent component
<parent-component
(rowClicked)="onGridRowClicked($event)"
[gridOptions]="gridOptions"
[callerClass]="this"
></parent component>
Child component
@Input() callerClass: any;
async createDatasource(): Promise<IServerSideDatasource> {
return {
getRows: async (params) => {
this.createRequestPayload(params.request);
const rowData = await this.callerClass.getPageData(
this.paging,
this.filterModel,
);
params.success({
rowData: rowData,
});
},
};
}
The code is working as expected but I want to know is there any better approach to achieve the same functionality.
Upvotes: 2
Views: 51
Reputation: 9124
You could inject the parent component.
import { Observable } from 'rxjs';
export abstract class AbstractParentComponent {
abstract getPageData(): Observable<string>;
}
import { Component, forwardRef } from '@angular/core';
import { Observable, of } from 'rxjs';
import { AbstractParentComponent } from './abstract-parent.component';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent-a',
standalone: true,
template: '<app-child></app-child>',
imports: [ChildComponent],
providers: [
{
provide: AbstractParentComponent,
useExisting: forwardRef(() => ParentAComponent),
},
],
})
export class ParentAComponent extends AbstractParentComponent {
getPageData(): Observable<string> {
return of('Data from parent A');
}
}
import { Component, forwardRef } from '@angular/core';
import { Observable, of } from 'rxjs';
import { AbstractParentComponent } from './abstract-parent.component';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent-b',
standalone: true,
template: '<app-child></app-child>',
imports: [ChildComponent],
providers: [
{
provide: AbstractParentComponent,
useExisting: forwardRef(() => ParentBComponent),
},
],
})
export class ParentBComponent extends AbstractParentComponent {
getPageData(): Observable<string> {
return of('Data from parent B');
}
}
import { AsyncPipe } from '@angular/common';
import { Component, inject } from '@angular/core';
import { AbstractParentComponent } from './abstract-parent.component';
@Component({
selector: 'app-child',
standalone: true,
template: '<div>{{ parentComponent.getPageData() | async }}</div>',
imports: [AsyncPipe],
})
export class ChildComponent {
protected parentComponent = inject(AbstractParentComponent);
}
Stackblitz: https://stackblitz.com/edit/stackblitz-starters-wbudrf?file=src%2Fparent-b.component.ts
Upvotes: 0
Reputation: 56297
Pass getPageData
directly into the child instead of this.
@Input() getPageData: Function;
async createDatasource(): Promise<IServerSideDatasource> {
return {
getRows: async (params) => {
this.createRequestPayload(params.request);
const rowData = await this.getPageData(
this.paging,
this.filterModel,
);
params.success({
rowData: rowData,
});
},
};
}
Then if necessary you can bind the parent scope using .bind(this)
so that it executes with the original context
<parent-component
(rowClicked)="onGridRowClicked($event)"
[gridOptions]="gridOptions"
[getPageData]="getPageData.bind(this)"
></parent component>
Upvotes: 1