2

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"
    };
}
}
Mark Rajcok
  • 348,511
  • 112
  • 482
  • 482
Marco Jr
  • 5,153
  • 8
  • 36
  • 72
  • 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 Mar 15 '16 at 14:57
  • "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 cookbook](https://angular.io/docs/ts/latest/cookbook/component-communication.html) – Mark Rajcok Mar 18 '16 at 19:37
  • The parent incorporates the child ny using import and the selector . 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 Mar 19 '16 at 18:53

3 Answers3

4

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.

Community
  • 1
  • 1
Mark Rajcok
  • 348,511
  • 112
  • 482
  • 482
  • ty, Mark !! I will check your answer 'til tomorrow and I will not forget to mark you as answer if applicable. ty ! – Marco Jr Mar 23 '16 at 18:04
  • Your solution is exactly what I'm doing actually. Honestly it's not much elegant, but looks like it's the only one acceptable :( For example, in my real project I've an inputBox in my parent .I need to cause a reaction (event) in my child event every time the user press the arrow key. It could be up and down. So, I'm using your solution in this way: if(event.keyCode ==40){ this.myChildProperty = 'down,' + Math.random(); } - If I press the down twice, the random will ensure that the event will be executed. But honestly I really don't like this solution. But since it's the only one acceptable,ok – Marco Jr Mar 25 '16 at 16:24
  • @MarcoS.Junior, since you keep mentioning the word "event", it sounds like the shared service approach (with an Observable or a Subject) would be more appropriate for your use case, rather than a input property. – Mark Rajcok Mar 25 '16 at 16:46
2

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>
Thierry Templier
  • 182,931
  • 35
  • 372
  • 339
  • Unable to implement: ngOnInit() { this.parentEventEmitter.subscribe((event) => { }); ---> this.parentEventEmitter.subscribe is not a function in [arrow in ParentComponent - I placed this on plunker at https://plnkr.co/edit/nqlCl6r5Ib64MCYJA5v9 – Marco Jr Mar 15 '16 at 19:28
1

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

Mohy Eldeen
  • 1,158
  • 2
  • 12
  • 22
  • Sounds really interesting, Mohy ! I will study this on monday, but I liked ! – Marco Jr Mar 19 '16 at 18:54
  • You set a value to the parent, basically. The challenge is to make the parent cause an event on child. In my example, I'm raising an event from the child to parent. – Marco Jr Mar 21 '16 at 08:50
  • Well, if you noticed I change the value from the parent and it reflects in the child and when I change it from the child it reflect into the parent. This is very much the 2-way communication. Are you looking to accomplish something different? – Mohy Eldeen Mar 21 '16 at 19:16