Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 : two way binding inside parent/child component

Tags:

angular

Version: "angular2": "2.0.0-beta.6"

I would like to implement a two way binding inside a parent/child component case.

On my child component, I'm using two-way binding to display text while editing.

Child component (InputTestComponent [selector:'input-test']):

<form (ngSubmit)="onSubmit()" #testform="ngForm">     {{name}}     <textarea #textarea [(ngModel)]="name" ngControl="name" name="name"></textarea>     <button type="submit">Go</button> </form> 

Then, I would like to propagate this change to his parent component. I tried with [(name)]="name" with no success.

Parent component:

<div>   {{name}}   <input-test [(name)]="name"></input-test> </div> 

Code sample

What the easiest way to do it (less verbose) ?

like image 853
plone1 Avatar asked Feb 25 '16 09:02

plone1


People also ask

Does angular2 support 2 way binding?

Angular v2+ supports two-way data binding using ngModel directive and also by having getter and setter methods.

How does a child component communicate with a parent component is it 2 way?

The <parent-component> serves as the context for the <child-component> . @Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.


2 Answers

For 2-way binding use @Input() and @Output(). The names should be propName and propNameChange to allow the shorthand binding syntax [(propName)]="someModel" otherwise you'd need the longer version [propName]="someModel" (propNameOtherOutputName)="propName=$event;propNameOtherOutputName.emit($event)"

@Component{   ...   template: ` <textarea #textarea [(ngModel)]="name" (ngModelChange)="nameChange.emit($event)" ngControl="name" name="name"></textarea>  `}) export class InputTestComponent {   @Output() nameChange:EventEmitter<String> = new EventEmitter<String>();   @Input() name:string; } 
like image 81
Günter Zöchbauer Avatar answered Oct 12 '22 13:10

Günter Zöchbauer


You can setup two-way data binding between parent and child component in the following ways:

<app-child [(counter)]="counter"></app-child> <app-child [counter]="counter" (counterChange)="counter=$event"></app-child> <app-child [counter]="counter" (counterChange)="onCounterChange($event)"></app-child> 

According to Angular - Template Syntax - Two-way binding:

Angular offers a special two-way data binding syntax for this purpose, [(x)]. The [(x)] syntax combines the brackets of property binding, [x], with the parentheses of event binding, (x).

<app-child [(counter)]="counter"></app-child> 

The [(x)] syntax is easy to demonstrate when the element has a settable property called x and a corresponding event named xChange.

@Input() counter: number; @Output() counterChange = new EventEmitter<number>(); 

The two-way binding syntax is really just syntactic sugar for a property binding and an event binding. Angular desugars the ChildComponent binding into this:

<app-child [counter]="counter" (counterChange)="counter=$event"></app-child> 

Example: https://stackblitz.com/edit/angular-two-way-data-binding-between-parent-and-child-component?file=src%2Fapp%2Fapp.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';  @Component({   selector: 'app-root',   template: `   <div style="background-color: red; padding: 10px;">     <div>{{counter}}</div>     <button (click)="increment()">increment from parent</button>     <app-child [(counter)]="counter"></app-child>     <app-child [counter]="counter" (counterChange)="counter=$event"></app-child>     <app-child [counter]="counter" (counterChange)="onCounterChange($event)"></app-child>   </div>   ` }) export class AppComponent {    counter = 0;    increment() {     this.counter++;   }    onCounterChange(counter: number) {     this.counter = counter;   } }  @Component({   selector: 'app-child',   template: `   <div style="background-color: green; padding: 10px; margin: 10px;">     <div>{{counter}}</div>     <button (click)="increment()">increment from child</button>   </div>   `, }) export class ChildComponent {    @Input() counter: number;   @Output() counterChange = new EventEmitter<number>();    constructor() { }    increment() {     this.counterChange.emit(++this.counter);   }  } 
like image 31
Milan Hlinák Avatar answered Oct 12 '22 13:10

Milan Hlinák