【问题标题】:Angular 2 property binding: how do EventEmitters work?Angular 2 属性绑定:EventEmitters 是如何工作的?
【发布时间】:2017-02-24 11:57:47
【问题描述】:

我一直在学习 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 事件在 EventEmitter 上调用 emit() 方法,其名称 cNameChange 派生自 cName 属性的名称:

@Output() public cNameChange:EventEmitter<String> = new EventEmitter<String>();

因此,如果您编辑第二个文本输入的值,则子项的 cName 属性会更改,其他两个文本输入项的值会更改,而父项的 pName 属性会更改。

但是,如何

这可以分为两个相关的问题:

  1. 发出该事件如何更改cName 属性?
  2. 更改子级的cName 属性会如何最终更改父级的pName 属性?

【问题讨论】:

    标签: javascript angular data-binding properties


    【解决方案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)]="pData" 以两种方式绑定到子cData。这意味着父级同时向子级提供@Input('cData') 监听cNameChange 事件,该事件自动 更改绑定属性,在本例中为@987654335 @。这是唯一真正神奇的部分。但这是 Angular 文档中描述的,所以我们只是接受它是真的。

    因此,当您输入第二个子输入时,它会根据 Angular 规范发出 cDataChange 事件并且 pData 会发生变化。 pData 也是 cData 的输入,因此 cData 也需要更改以匹配 pData 输入。

    您可以通过注释掉孩子的第一个和第三个输入来确认父母对cData的更改负责,然后添加

    <li>cName: {{ cName }}</li>
    
    1. 更改子级的cName 属性会如何最终更改父级的pName 属性?

    您在任何时候都没有真正(明确地)改变它。这一切都由双向绑定处理。如果你添加的东西确实明确地改变了它,说

    <button (click)="cName = 'hello'">Change</button>
    

    或者只是简单地输入第三个输入。当您单击按钮或键入时,您会看到它不会更改父级,但子级会看到更改,因为他们从cData 获取输入。只有在cDataChange 事件与新值一起发出时,父级才能看到更改是cData

    所以实际上改变父节点的是上一点讨论的活动。

    【讨论】:

    • 感谢您的回答,但我希望的不仅仅是“相信魔法”。例如,我的下一个问题是为什么第三个文本输入(与[(ngModel)] 绑定)会更改子属性而不是父属性。看起来魔法不起作用;我该怎么办?
    • 就您的担忧而言,这不是一个“相信魔法”的答案。我提到的唯一魔法是,从[()] 语法中,当更改通过cDataChange 发出时,Angular 会在输入端为我们更改值。这是在文档中指定的,任何进一步的详细说明都意味着解释内部源代码,这对于解决您的问题中的问题不是必需的。
    • 至于您的第三个问题,已在帖子中解决。父 pData 仅在 cDataChange 事件上未注明日期。第三个盒子永远不会触发
    • 也许你错过了[(cData)]只是[cData]="" (cDataChange)=""的简写就像[(ngModel)][ngModel]="" (ngModelChange)=""的简写一样的理解
    • 那么,[ngModel]="..." (ngModelChange)="..." 的第二个示例与[(ngModel)]="..." 的第三个示例相同,对吧?那么为什么它们的行为不同(即第二个更改父值,第三个没有)?
    猜你喜欢
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    • 1970-01-01
    • 2018-02-14
    • 2016-07-21
    • 2016-10-05
    • 2019-04-08
    相关资源
    最近更新 更多