22

I have a Submitbutton in the parent component namelypersonDetails.personDetailshas manyperson` components. Whenever I click on the Submit button, I want to call a method in child component.

How can I emit an event from a parent to a child component using @Output?

Its easy to do it from the child to the parent. I want to access a value of the child component, hence I need to emit an event from parent to child.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
raj m
  • 1,863
  • 6
  • 21
  • 37

2 Answers2

40

You can create one service which is shared between your parent and child component in which you can define Observable so that you can subscribe to that Observable from child and perform some action when you receive some value from parent.

//common.service.ts

import { Injectable, Inject } from '@angular/core';
import { Subject }    from 'rxjs/Subject';
@Injectable()
export class CommonService {
  private notify = new Subject<any>();
  /**
   * Observable string streams
   */
  notifyObservable$ = this.notify.asObservable();

  constructor(){}

  public notifyOther(data: any) {
    if (data) {
      this.notify.next(data);
    }
  }
}

//parent.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { CommonService } from './common.service';

@Component({
  selector   : 'parent',
  templateUrl : './parent.html'
})
export class ParentComponent implements OnInit, OnDestroy {
  constructor( private commonService: CommonService ){
  }

  ngOnInit() {
    this.commonService.notifyOther({option: 'call_child', value: 'From child'});
  }
}

//child.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { CommonService } from './common.service';

@Component({
  selector   : 'child',
  templateUrl : './child.html'
})
export class ChildComponent implements OnInit, OnDestroy {
  private subscription: Subscription;
  constructor( private commonService: CommonService ){
  }

  ngOnInit() {
    this.subscription = this.commonService.notifyObservable$.subscribe((res) => {
      if (res.hasOwnProperty('option') && res.option === 'call_child') {
        console.log(res.value);
        // perform your other action from here

      }
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
ranakrunal9
  • 13,320
  • 3
  • 42
  • 43
  • 1
    please go through this link... http://stackoverflow.com/questions/39717465/how-to-read-directive-model-value-in-its-main-controller-using-angular2/39719175?noredirect=1#comment66739597_39719175.. Here I have mentioned parent and child component. Please tell me how can I access that personDetails object in parent. Or how can I call the submit method in child.. This question is similar this link – raj m Sep 28 '16 at 08:53
  • How to attach a event from parent html to child.. For example there is a submit button in parent, when I click it how can fire it in child. Instead of ngOnInit() can I use submit() ? – raj m Sep 28 '16 at 09:31
  • when you click on submit from `parent` then call `notifyOther` of `commonService` with some params and check that params value in `child` by subscribing it and based on params value call you action of child. – ranakrunal9 Sep 28 '16 at 09:34
  • I am getting No provider for CommonService! error.. Should I add any providers – raj m Sep 28 '16 at 09:38
  • You have to add `CommonService` in your module or component's provider metadata declaration – ranakrunal9 Sep 28 '16 at 09:40
  • @ranakrunal9, I did exactly the same but unfortunately my code is not working. Another thing is you've defined `notifyObservable$` as a observable but in child component you subscribe with `submitObservable$`. – Emu Oct 26 '16 at 10:40
  • @ranakrunal9, no error but the problem i'm facing is, my service is passing the data to parent component with `next`, but in the parent ngOnInit, the subscribe portion is not being hit. Any guesses? – Emu Oct 26 '16 at 10:47
  • if you have added condition on `res` inside `subscribe` then remove it and check it once and make sure you share same instance of `CommonService` in your parent and child component – ranakrunal9 Oct 26 '16 at 10:49
  • The answer provided by @ranakrunal9 is correct. Subjects can act like EventListeners . And that in a way can be used for sending an event listener in child, a value from the parent. And the preferred way of achieving this is by using Subject and not a plain Observable – vijayakumarpsg587 Nov 20 '19 at 17:36
20

Child Component

In childComponent.ts

@Input() private uploadSuccess: EventEmitter<boolean>;

Additionally in childComponent.ts subscribe to the event:

ngOnInit() {
  if (this.uploadSuccess) {
    this.uploadSuccess.subscribe(data => {
      // Do something in the childComponent after parent emits the event.
    });
  }
}

Parent Component

In ParentComponent.html

<app-gallery  [uploadSuccess] = "uploadSuccess" > </app-gallery>

In ParentComponent.ts

private uploadSuccess: EventEmitter<boolean> = new EventEmitter();

onImageUploadSuccess(event) {
   console.log('Image Upload succes');
   if (event.code === 'OK' && this.maxUploadLimit > 0) {
      this.galleryImagesCount = this.galleryImagesCount + 1;
      this.maxUploadLimit = this.maxUploadLimit - 1;
    }

   // The parent emits the event which was given as `@Input` variable to the child-component
   this.uploadSuccess.emit(true);
}
Tarator
  • 1,517
  • 1
  • 13
  • 30
Ali Azhar
  • 1,703
  • 19
  • 14
  • perfect comment. Only little change to succed fully check from typescript add "!": @Input() private uploadSuccess!: EventEmitter; – x-magix Jul 25 '19 at 09:17