【问题标题】:Angular2 : two way binding inside parent/child componentAngular2:父/子组件内的两种方式绑定
【发布时间】:2016-06-08 00:35:35
【问题描述】:

版本:“angular2”:“2.0.0-beta.6”

我想在父/子组件案例中实现双向绑定。

在我的子组件上,我使用双向绑定在编辑时显示文本。

子组件(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>

然后,我想将此更改传播到他的父组件。 我尝试了[(name)]="name",但没有成功。

父组件:

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

Code sample

最简单的方法是什么(不那么冗长)?

【问题讨论】:

    标签: angular


    【解决方案1】:

    对于 2 向绑定,请使用 @Input()@Output()。名称应为 propNamepropNameChange 以允许使用速记绑定语法 [(propName)]="someModel" 否则您需要更长的版本 [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;
    }
    

    【讨论】:

    • 工作......你忘了提到需要对父子属性进行香蕉绑定
    • 这不是盒装亲子香蕉的例子。
    • 当然是 - &lt;textarea&gt; 是子组件,可以是自定义组件。
    • 对我来说(角度为 6)只有在我指定了 2-way-binded 道具的名称后才有效:在 component.ts 中:@Input('selected') selected; @Output('selectedChange') selectedChange:EventEmitter&lt;any&gt; = new EventEmitter&lt;any&gt;();,在 component.html 中:@ 987654330@,在使用该组件的模板中:&lt;component ... [(selected)]="formFields.okpdCode"&gt;&lt;/component&gt;
    【解决方案2】:

    您可以通过以下方式在父子组件之间设置双向数据绑定:

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

    根据Angular - Template Syntax - Two-way binding

    Angular 为此提供了一种特殊的双向数据绑定语法, [(X)]。 [(x)] 语法结合了属性绑定的括号, [x],带括号的事件绑定,(x)。

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

    当元素具有 名为 x 的可设置属性和名为 xChange 的相应事件。

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

    双向绑定语法实际上只是一个语法糖 属性绑定和事件绑定。 Angular 脱糖 ChildComponent 绑定到这个:

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

    示例: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);
      }
    
    }
    

    【讨论】:

      【解决方案3】:

      您需要在子组件中使用输入/输出元素,如下所述:

      @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();
      }
      

      当检测到更改时,您需要使用EventEmitter 触发事件:

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

      这样使用以下语法时,父组件的绑定元素会自动更新:

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

      您可以注意到,如果您想检测输入更改而不是使用表单提交,您可以利用 ngModelChange 事件:

      @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);
        }
      }
      

      【讨论】:

      • 在上一个代码 sn-p 中,由于您使用 [ngModel] 而不是 [(ngModel)](我更喜欢您所做的),因此您的 onChange() 事件处理程序需要更新 this.name 时事件触发:onChange($event) 然后onChange(newValue) { this.name = newValue; this.nameChange.emit(this.name);}
      【解决方案4】:

      是的,我们可以使用香蕉属性在孩子与父母之间共享数据 [(propertyname)]propertynameChange 发射器事件。 样品 plunker 可用https://plnkr.co/edit/FYXv36?p=preview

      【讨论】:

        【解决方案5】:

        您可以使用 @Input 和 @Output 来实现父子之间的 2 路绑定,如前面的答案中所述。

        否则,还有另一种解决方案,您可以使用包含您的变量的服务,并且您可以同时使用 ngModel 从不同的组件访问它(即使它们不是父子组件)

        【讨论】:

          猜你喜欢
          • 2016-06-08
          • 2017-08-06
          • 1970-01-01
          • 2016-04-21
          • 1970-01-01
          • 2020-07-12
          • 2021-10-16
          • 1970-01-01
          相关资源
          最近更新 更多