我一直在研究Angular 2双向绑定,并且我已经整理了一个演示,它将组件的属性绑定到另一个,包含组件的属性,以及几个文本字段。不幸的是,对我来说很多看起来像是magic,这使得当魔法不起作用时调试非常困难。特别是,该演示揭示了我尚未完全理解绑定的几个地方;这个问题是关于这一主题的第一个问题。
(演示位于http://plnkr.co/edit/IUTy5p?p=preview,以防您想在家中跟进......)
该代码实现了一个父组件,其中包含pName
字符串属性,以及一个包含cName
属性的子组件。父项的属性使用香蕉盒语法双向绑定到子项的属性:
<child [(cName)]="pName"></child>
子项内部显示cName
属性,以及三个文本输入,每个输入都以某种方式绑定到cName
属性。第二个文本输入是重要的一个:
<input type="text" [ngModel]="cName" (ngModelChange)="cNameChange.emit($event)">
ngModelChange
事件在emit()
上调用EventEmitter
方法,其名称cNameChange
来自cName
媒体资源的名称:
@Output() public cNameChange:EventEmitter<String> = new EventEmitter<String>();
因此,如果您编辑第二个文本输入的值,则子项的cName
属性会更改,其他两个文本输入会更改其值,并且父项的pName
属性会更改。
但是,如何?
这可以分为两个相关的问题:
cName
属性?cName
属性最终更改父级pName
属性?答案 0 :(得分:1)
唯一真正的魔力是[()]
语法,由Angular指定。其余部分可在以下部分中解释
当我们使用[(cData)]="pData"
时,它与使用
[cData]="pData" (cDataChange)="pData = $event"
当事件发送到cDataChange
时,Angular保证将绑定输入属性([cData]="pData"
)的值(在本例中为pData
)设置为cDataChange
发出的值{1}}
- 如何排放该事件会改变
醇>cName
属性?
@Component({
template: `
<input type="text" [ngModel]="cName" (ngModelChange)="cNameChange.emit($event)">
`
})
export class ChildComponent {
@Input() public cName:string = 'thisIsIgnored';
@Output() public cNameChange:EventEmitter<String> = new EventEmitter<String>();
}
@Component({
selector: 'parent',
template: `
<child [(cName)]="pName"></child>
`
})
export class App {
pName:string;
constructor() {
this.pName = 'InitialName'
}
}
使用简化语法pData
,父cData
与儿童[(cData)]="pData"
双向绑定。这意味着父级同时向{em> 提供了@Input('cData')
并且提供了cNameChange
事件,其中自动更改了绑定属性,这种情况pData
。这是唯一真正神奇的部分。但它是Angular docs中描述的内容,所以我们只接受它为真。
因此,当您输入第二个子输入时,它会根据Angular规范发出cDataChange
事件并更改pData
。 pData
也是cData
的输入,因此cData
也需要更改以匹配pData
输入。
您可以通过注释掉孩子的第一个和第三个输入,然后添加
来确认父母负责cData
更改
<li>cName: {{ cName }}</li>
- 如何更改子级
醇>cName
属性最终更改父级pName
属性?
在任何时候你都没有真正改变它(明确地)。这都是双向绑定处理的。如果您添加了 明确更改的内容,请说
<button (click)="cName = 'hello'">Change</button>
或只是输入第三个输入。当您单击按钮或键入时,您将看到不更改父级,但子级会看到更改,因为他们正在从cData
获取输入。只有在使用新值发出cData
事件时,父级才会看到更改的唯一方法是cDataChange
。
那么实际上改变父亲的是前一点讨论的活动。