Angular 2 ngModel in child component updates parent component property
I made a simple UI which consist two components (parent and child).
What the UI does is that when I type some stuff in the input box of the Child component. The value will change using ngModel.
The child component works fine that way.
// Child Component
@Component({
selector: 'child',
template: `
<p>{{sharedVar}}</p>
<input [(ngModel)]="sharedVar">
`
})
export class ChildComponent {
sharedVar: string;
}
Now I have a parent component which I intend to use the same value as Child Component.
I added the Child Component into the Parent template, and use dependency injection to call Child Component's sharedVar
.
// Parent Component
@Component({
selector: 'parent',
template: `
<h1>{{sharedVar}}</h1>
<child></child>
`,
directives: [ChildComponent],
providers: [ChildCompnent]
})
export class ParentComponent {
sharedVar: string;
constructor(child: ChildComponent) {
this.sharedVar = child.sharedVar;
}
}
The problem is as I'm typing in the input box, the value in <p>
changes automatically while the value in parent component's <h1>
do not change.
We can use the [(x)]
syntax in the parent template to achieve two-way databinding with the child. If we create an Output property with the name xChange
, Angular will automatically update the parent property. We do need to emit()
an event whenever the child changes the value however:
import {Component, EventEmitter, Input, Output} from 'angular2/core'
@Component({
selector: 'child',
template: `
<p>Child sharedVar: {{sharedVar}}</p>
<input [ngModel]="sharedVar" (ngModelChange)="change($event)">
`
})
export class ChildComponent {
@Input() sharedVar: string;
@Output() sharedVarChange = new EventEmitter();
change(newValue) {
console.log('newvalue', newValue)
this.sharedVar = newValue;
this.sharedVarChange.emit(newValue);
}
}
@Component({
selector: 'parent',
template: `
<div>Parent sharedVarParent: {{sharedVarParent}}</div>
<child [(sharedVar)]="sharedVarParent"></child>
`,
directives: [ChildComponent]
})
export class ParentComponent {
sharedVarParent ='hello';
constructor() { console.clear(); }
}
Plunker
I used sharedVarParent
in the ParentComponent just to demonstrate that the names don't have to be the same in the parent and child.
You could set up event emitter communication (outputs
) from child to parent. For example like this:
@Component({
selector: 'child',
template: `
<p>Child: {{sharedVar}}</p>
<input [(ngModel)]="sharedVar" (ngModelChange)="change()">
`
})
export class ChildComponent {
@Output() onChange = new EventEmitter();
sharedVar: string;
change() {
this.onChange.emit({value: this.sharedVar});
}
}
and the in parent component:
@Component({
selector: 'parent',
template: `
<h1>{{sharedVar}}</h1>
<child (onChange)="sharedVar = $event.value"></child>
`,
directives: [ChildComponent]
})
export class ParentComponent {
sharedVar: string;
constructor() {
}
}
Demo: http://plnkr.co/edit/T2KH4nGKPSy6GEvbF1Nb?p=info
And if you want to have multiple two-way databindings in the same component, you can do
export class ComponentName {
@Input() public first: string = '';
@Input() public second: string = '';
@Output() public firstChange = new EventEmitter();
@Output() public secondChange = new EventEmitter();
public functionName1(first: string): void {
this.first = first;
this.firstChange.emit(first);
}
public functionName2(second: string): void {
this.second = second;
this.secondChange.emit(second);
}
}
When input and output are named 'x' and 'xChange', it detects them automatically in the parent belonging together.
I think this is actually a better practice than the one in the accepted answer, because here it makes immediately clear how the names are related.