Angular2 : two way binding inside parent/child component

后端 未结 5 969
天涯浪人
天涯浪人 2020-12-09 08:24

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 t

相关标签:
5条回答
  • 2020-12-09 09:10

    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);
      }
    
    }
    
    0 讨论(0)
  • 2020-12-09 09:15

    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;
    }
    
    0 讨论(0)
  • 2020-12-09 09:20

    You need to use input / output elements in the child component, as described below:

    @Component({
      selector:'input-test'
      template: `
        <form (ngSubmit)="onSubmit()" #testform="ngForm">
        {{name}}
          <textarea #textarea [(ngModel)]="name" ngControl="name" name="name"></textarea>
          <button type="submit">Go</button>
        </form>
      `
    })
    export class InputTestComponent {
      @Input()
      name:string;
    
      @Output()
      nameChange:EventEmitter<string> = new EventEmitter();
    }
    

    When a change is detected, you need to fire an event using the EventEmitter:

    onSubmit() {
      this.nameChange.emit(this.name);
    }
    

    This way the bound element of the parent component will be automatically updated when using the following syntax:

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

    You can notice that you can leverage, the ngModelChange event if you want to detect input change instead of using form submission:

    @Component({
      selector:'input-test'
      template: `
        <form #testform="ngForm">
        {{name}}
          <textarea #textarea [ngModel]="name" (ngModelChange)="onChange($event)" ngControl="name" name="name"></textarea>
        </form>
      `
    })
    export class InputTestComponent {
      @Input()
      name:string;
    
      @Output()
      nameChange:EventEmitter<string> = new EventEmitter();
    
      onChange(newName) {
        this.name = newName;
        this.nameChange.emit(this.name);
      }
    }
    
    0 讨论(0)
  • 2020-12-09 09:22

    Yes we can use banana property to share the data between child to parent [(propertyname)] and propertynameChange emitter event. Sample plunker available https://plnkr.co/edit/FYXv36?p=preview

    0 讨论(0)
  • 2020-12-09 09:29

    You can use @Input & @Output to achive 2 way binding between parent and child as mentioned in previous answers.

    Otherwise, there another solution, you can use a service that contains your variable, and you can access it with ngModel in the same time from different components (even if they are not parent-child)

    0 讨论(0)
提交回复
热议问题