Reputation: 8999
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?
Upvotes: 222
Views: 249045
Reputation: 1420
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.
}
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> = new 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.
});
Upvotes: 141
Reputation: 194
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
Upvotes: 0
Reputation: 232
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.
}
}
}
Upvotes: 3
Reputation: 4564
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();
}
Upvotes: 439
Reputation: 3949
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 })
Upvotes: 76
Reputation: 1499
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.
Upvotes: 1
Reputation: 411
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
Upvotes: 10