Home > Mobile >  Angular 11 - Call parent function from child
Angular 11 - Call parent function from child

Time:07-06

I have used the passing of values ​​between Angular components several times correctly (Input/Output), but I found the following particular situation and I cannot find the solution:

I have two components:

  1. home.component (parent component)

The parent component, which in turn, contains another navigation component between tabs obtained from an external library, which is the one that loads the child component in a tab: "task.component":

html file:

<div>
<app-tabs [tabs]="tabs" [activeTab]="activeTab" (id)="onId($event)"></app-tabs>
</div>

ts file:

onId($event) {
    // $event would contain the id obtained in the child component
}
  1. tasks.component (child component)

The child component contains the call from a button to call the parent component:

html file:

<button type="button" (click)="play('task/play', 30)">Play</button>

ts file:

@Output() id= new EventEmitter<number>();
play(url: string, id: number) {
this.tasksService.playTask(url).subscribe(
  response => {
    // From here, I need to communicate with the parent and access a method that is in the parent.
    // this.id.emit(id);
  },
  err => {
  }
);
}

In other cases, I pass parameters from the child to the parent without problems because I use my own components, but when using an intermediate tab component I do not get it. (is mandatory to use the tab component). I think it's logical that it doesn't work because the "Output" has to be passed directly to the component "task.component". That is, I cannot pass the "Output" "id" to the "app-tabs" component.

How could I do it?

CodePudding user response:

It seems that child component (or grandchild component) is contained in a child route.

In this case, one solution could be to use a shared service to send notification from child component to parent. (or any other component inside application).

To do that, we need an injectable service (or integrated into an existing service) :

in notification.service.ts :

@Injectable()
export class NotificationService {
  _taskPlayed$ = new Subject<number>();

  get taskPlayed$() {
    return this._taskPlayed$.asObservable();
  }

  taskPlayed(id: number) {
    this._taskPlayed$.next(id);
  }
}

Be sure to add this service in module providers.

Then, we can inject service in child (or any component), and call taskPlayed method in order to emit a new value/event in observable.

So, in child.component.ts :

export class ChildComponent {
  constructor(private notificationService: NotificationService) {}

  playTask() {
    this.notificationService.taskPlayed(1);
  }
}

Same thing, we inject service in parent (or any component in app), and subscribe to taskPlayed$ observable from service. (be sure to unsubscribe when component is destroyed).

So, in parent.component.ts :

export class ParentComponent implements OnInit, OnDestroy {
  subscription!: Subscription;

  constructor(private notificationService: NotificationService) {}

  ngOnInit(): void {
    this.subscription = this.notificationService.taskPlayed$.subscribe((id) => {
      // do something with id...
      ....
    });
  }

  ngOnDestroy(): void {
    this.subscription?.unsubscribe();
  }
}

In this example, only id value is sent via Observable, but we can also pass a more complex object.

export class NotificationService {
  _taskPlayed$ = new Subject<{ id: number, title: string }>();

  get taskPlayed$() {
    return this._taskPlayed$.asObservable();
  }

  taskPlayed(task: {id: number, title: string}) {
    this._taskPlayed$.next(task);
  }
}
  • Related