How to emit an event from parent to child?

AngularTypescript

Angular Problem Overview


I am currently using Angular 2. Usually we use @Output() addTab = new EventEmitter<any>(); and then addTab.emit() to emit an event to parent component.

Is there any way we can do it vice cersa, from parent to child?

Angular Solutions


Solution 1 - Angular

Using RxJs, you can declare a Subject in your parent component and pass it as Observable to child component, child component just need to subscribe to this Observable.

Parent-Component

eventsSubject: Subject<void> = new Subject<void>();

emitEventToChild() {
  this.eventsSubject.next();
}

Parent-HTML

<child [events]="eventsSubject.asObservable()"> </child>    

Child-Component

private eventsSubscription: Subscription;

@Input() events: Observable<void>;

ngOnInit(){
  this.eventsSubscription = this.events.subscribe(() => doSomething());
}

ngOnDestroy() {
  this.eventsSubscription.unsubscribe();
}

Solution 2 - Angular

As far as I know, there are 2 standard ways you can do that.

1. @Input

Whenever the data in the parent changes, the child gets notified about this in the ngOnChanges method. The child can act on it. This is the standard way of interacting with a child.

Parent-Component
public inputToChild: Object;
        
Parent-HTML
<child [data]="inputToChild"> </child>       
        
Child-Component: @Input() data;

ngOnChanges(changes: { [property: string]: SimpleChange }){
   // Extract changes to the input property by its name
   let change: SimpleChange = changes['data']; 
// Whenever the data in the parent changes, this method gets triggered. You 
// can act on the changes here. You will have both the previous value and the 
// current value here.
}

2. Shared service concept

Creating a service and using an observable in the shared service. The child subscribes to it and whenever there is a change, the child will be notified. This is also a popular method. When you want to send something other than the data you pass as the input, this can be used.

SharedService
subject: Subject<Object>;

Parent-Component
constructor(sharedService: SharedService)
this.sharedService.subject.next(data);

Child-Component
constructor(sharedService: SharedService)
this.sharedService.subject.subscribe((data)=>{

// Whenever the parent emits using the next method, you can receive the data 
in here and act on it.})

Solution 3 - Angular

In a parent component you can use @ViewChild() to access child component's method/variable.

@Component({
  selector: 'app-number-parent',
  templateUrl: './number-parent.component.html'
})
export class NumberParentComponent {
    @ViewChild(NumberComponent)
    private numberComponent: NumberComponent;
    increase() {
       this.numberComponent.increaseByOne();
    }
    decrease() {
       this.numberComponent.decreaseByOne();
    }
} 

Update:

Angular 8 onwards -

@ViewChild(NumberComponent, { static: false })

Solution 4 - Angular

Use the @Input() decorator in your child component to allow the parent to bind to this input.

In the child component you declare it as is :

@Input() myInputName: myType

To bind a property from parent to a child you must add in you template the binding brackets and the name of your input between them.

Example :

<my-child-component [myChildInputName]="myParentVar"></my-child-component>

But beware, objects are passed as a reference, so if the object is updated in the child the parent's var will be too updated. This might lead to some unwanted behaviour sometime. With primary types the value is copied.

To go further read this :

Docs : https://angular.io/docs/ts/latest/cookbook/component-communication.html

Solution 5 - Angular

Within the parent, you can reference the child using @ViewChild. When needed (i.e. when the event would be fired), you can just execute a method in the child from the parent using the @ViewChild reference.

Solution 6 - Angular

None of the previous solutions worked for me because I had a Nested Recursive Child Component. So I used the following approach by using the OnChanges function.

Parent Component

buttonToggle: boolean = false;

buttonClick(): void {
  this.buttonToggle = !this.buttonToggle;
}

Parent HTML

<appNestedChildItemComponent [buttonTrigger]="buttonToggle"></appNestedChildItemComponent>

Recursive Nested Child Component

export class NestedChildItemComponent implements OnInit, OnChanges {

  @Input() buttonTrigger: boolean;
  buttonToggle: boolean = false;

  ngOnInit() {
    this.buttonToggle= buttonToggle;
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes['buttonTrigger'] && changes['buttonTrigger']?.previousValue != changes['buttonTrigger']?.currentValue) {
      this.buttonToggle= !this.buttonToggle;
      // Do Something triggered by the parent button.
    }
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questioncode1View Question on Stackoverflow
Solution 1 - AngularBlueNCView Answer on Stackoverflow
Solution 2 - Angularprajwal gonsalvesView Answer on Stackoverflow
Solution 3 - AngularHardik PatelView Answer on Stackoverflow
Solution 4 - AngularNokiView Answer on Stackoverflow
Solution 5 - AngularPaul EvansView Answer on Stackoverflow
Solution 6 - AngularnesterenesView Answer on Stackoverflow