2
votes

I've this code...It's a sample tutorial application I'm trying to build that's reflect the daily basis needs of a developer. Actually, when the user types "fire" on the parent component, the child execute an event that's sends to the parent the word "booom" - It's a sample to demonstrate communication between a child component sending messages to a parent component using @Input and OnChanges.

Now, I'm trying to do different: The parent should with some how tell to the child a message like "Target Locked" to the child when the user press the enter key (keyCode == 13). With this we will have a scenario of 2 way communication between components.

What is the best approach ?

child.component

import {Component, Input, OnChanges, EventEmitter,Output, Injectable} from 'angular2/core';
@Injectable()
@Component({
selector: 'child-component',
template: `<p>I'm the child component</p>
`
})
export class ChildComponent implements OnChanges { 
@Input() txt: string;
@Output() aim: EventEmitter<any> = new EventEmitter();
ngOnChanges(changes: {[propName: string]: SimpleChange}) {
    var t = changes['txt'].currentValue;
    if(t == 'fire') {
        console.log('Fire !!!');
        this.aim.emit("booom !!!");
    }
}
}

parent.component

import {Component} from 'angular2/core';
import {ChildComponent} from './child.component'
@Component({
selector: 'parent-component',
directives : [ChildComponent]
template: `<p>I'm the parent component</p>
<input type="textbox" [(ngModel)]="theModel" (keydown)="arrow($event)">
<p>feedback: {{feedback}}</p>
<child-component txt="{{theModel}}" (aim)="feedback=$event"></child-component>
`
})
export class ParentComponent { 
theModel;
feedback;
arrow (evt){
    if(evt.keyCode ==13) {
        //Need to cause an event on the child - a message like "Target Locked"
    };
}
}
3
Use @Input() to communicate from the parent to the child, and @Output() to communicate from the child to the parent, or use a service.Eric Martinez
"Now, I'm trying to do different:" -- I don't see what is different here. Just use the same input and output properties and send different messages, or add another set of input and output properties. Also checkout the Component Interaction cookbookMark Rajcok
The parent incorporates the child ny using import and the selector <child-component>. So, the parent can capture the (aim) event from the child. My doubt is about to do the opposite way: Child capture the event of the parent. Remember the child will never have the selector of the parent. That's why it's really different. got the point ?Marco Jr

3 Answers

4
votes

My doubt is about to do the opposite way: Child capture the event of the parent. Remember the child will never have the selector of the parent. That's why it's really different.

I think the confusion is around the fact that you don't need an event. For parent → child communication, just add another input property to the child. And bind a parent property to it:

<child-component [anotherInputProperty]="someParentProperty" ...

Then, whenever you change the value of someParentProperty in the parent component, Angular change detection will propagate the new value to the child:

if(evt.keyCode === 13) {
    // Need to cause an event on the child - a message like "Target Locked".
    // Just change the property value:
    this.someParentProperty = "some new value";
    // Angular will take care of propagating the new value to the child
};

If you want the child to execute some logic when the input property value changes, implement ngOnChanges() in the child.

If the issue is that you don't want to change the message each time, then you could either

  • use a shared service with an Observable and have the child subscribe() to the Observable, or
  • prefix or postfix the message with a random value, and separate it from the message with a | or some other character you can split on, so that in the child you can easily extract the message.

You can also use a Subject rather than an Observable in the shared service: see Parent and children communicate via a service.

3
votes

You could provide an EventEmitter as input of the child component:

@Component({
  selector: 'child-component'
  (...)
})
export class ChildComponent {
  @Input()
  parentEventEmitter:EventEmitter;

  ngOnInit() {
    this.parentEventEmitter.subscribe((event) => {

    });
  }
}

The child could then subscribe on it to be notified...

This EventEmitter would be provided this way within the parent component:

<child-component
   [parentEventEmitter]="theEventEmitterFromTheParent">
</child-component>
1
votes

You need to implement event emitter and subscribe to it in the parent component. Your emitter name have to match the bound value name +'Change' Example: if your value name is "sum" your event need to be "sumChange" that way you can do 2 way binding from the parent liike [(sum)] = "value". Here is a plunk example:

https://plnkr.co/edit/efOGIJ0POh1XQeRZctSx?p=preview