Ritik Sahu
Ritik Sahu

Reputation: 21

Calling asynchronous function from parent component

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

Answers (2)

MoxxiManagarm
MoxxiManagarm

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

Naren Murali
Naren Murali

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

Related Questions