How to emit an event from parent to child?

Viewed 168729

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?

7 Answers

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();
}

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 })

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.

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.
    }
  }
}

On the same concept of shared services: one can also use a local store with property management. Parent(s) will update the state in the store and child(ren) may subsribe(s) to the store itself.

This approach makes it easier for many-to-many event/data/info transfers and can be applied the original question.

Drawback: heavier Advantage: more robust to big app evolutions

One example of store management library I would recommend: https://github.com/ngneat/elf

Related