【问题标题】:Angular2 two-way data bindingAngular2双向数据绑定
【发布时间】:2015-08-08 16:51:27
【问题描述】:

我知道 Angular2 没有双向数据绑定,但有没有办法模仿 Angular1.x 的双向数据绑定行为?

【问题讨论】:

  • 消除双向数据绑定的原因是因为它是一个根本存在缺陷的架构,所以是的,你可以这样做,但你不想这样做。
  • 关于周期和性能的问题?但是假设我确实想要这个特殊情况,我该怎么做呢?
  • 我在页面某处有一个标签和一个允许更改标签的文本框。如果我在文本框中输入,标签应该会改变。这不是真正的双向,当我想到它时......但我仍然不知道如何实现这个......

标签: data-binding 2-way-object-databinding angular


【解决方案1】:

这是一个简单的 plunker,它根据 Angular2 2.0.0-beta.17

演示了一种方式、两种方式和事件驱动的方法。

http://plnkr.co/eXZMoU

双向事件和属性

<input [(ngModel)]="name" />

单向属性

<input [value]="name" />

事件驱动

<input (input)="name=$event.target.value">

我们可以为 more 挖掘 Angular 文档

[2020 年 1 月 26 日更新]

由于 Angular2 beta 库已从项目 CDN 中删除!上面的 plnkr 链接已经失效了。

在新的 plnkr Angular 6+ 页面下方使用,我将上一页移植到 NPMJS、新的 Angular 版本和新的 plnkr!

http://next.plnkr.co/edit/4okdOSgw3SMvdktR?preview

【讨论】:

    【解决方案2】:

    来自文档:

    双向绑定([(...)]

    您通常希望在用户进行更改时既显示数据属性又更新该属性。

    在元素方面,它结合了设置特定元素属性和监听元素更改事件。

    Angular 为此提供了一种特殊的双向数据绑定语法[(x)][(x)] 语法将属性绑定的括号 [x] 与事件绑定的括号 (x) 组合在一起。

    [( )] = BANANA IN A BOX
    

    在一个盒子里想象一根香蕉,记住括号放在括号内。

    有关详细信息,请参阅

    【讨论】:

      【解决方案3】:

      是的,angular2 中有双向绑定。见这里:https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel

      那么,如何在自定义组件中使用呢?

      我喜欢做的是这样的:

      private currentSelectedItem: MachineItem;
      @Output() selectedItemChange: EventEmitter<MachineItem> = new EventEmitter<MachineItem>();
      
      @Input() set selectedItem(machineItem: MachineItem) {
          this.currentSelectedItem = machineItem;
          this.selectedItemChange.emit(machineItem); 
      }
      
      get selectedItem(): MachineItem {
          return this.currentSelectedItem; 
      }
      

      并像使用它一样

      <admin-item-list [(selectedItem)]="selectedItem"></admin-item-list>
      

      您还可以在实际更改的位置发出新值。但是我发现在 setter 方法中全局执行此操作非常方便,并且不必费心,例如当我将它直接绑定到我的视图时。

      【讨论】:

      • 这是迄今为止我为这个问题找到的最明智的答案,但不幸的是,我无法为此设置初始值(如果有一个 selectedItem 开头), selectedItem 没有设置
      • 不知道我的问题是否正确,但你不能设置 currentSelectedItem(不会发出事件)或在 ctor 中设置 selectedItem 吗?
      • 我之前确实尝试过,不幸的是事件确实被发射了,所以你陷入了无限循环
      • currentSelectedItem=xyz 发出了事件?
      • 请注意,输出发射器的名称很重要。它必须是“selectedItemChange”才能工作。规则是,如果您的输入是“x”,则输出发射器应命名为“xChange”,以使香蕉在盒子语法中起作用。我一直在努力解决这个问题,直到我看到这篇文章提到了这个事实。 bytes.vokal.io/20160509-angular-data-binding
      【解决方案4】:

      您现在可以通过使用以下语法使用 ngModel 来简单地执行此操作:

      <input [(ngModel)]="myProp" />
      

      方括号和圆括号的组合表示“双向绑定”。

      请看plunkhere

      【讨论】:

        【解决方案5】:

        很简单,试试这个;

        <input [(ngModel)]="property" placeholder="property Value"/>
        <h1>{{property}}</h1>
        

        【讨论】:

          【解决方案6】:

          注意 - 向下滚动 ng-model 绑定的答案

          您实际上可以这样做,只是您需要调用内部 changelistener tick(类似于摘要)来更新区域中的绑定,您只需为此添加一个 (keyup) 事件。同样,您也可以使用指令绑定以及 properties 组件设置字典。

          例子:-

          <input #label (keyup)> 
          <!-- variable #label represented as the element itself and accessible as property on controller instance 
           You can even bind keyup to a function or another another function and pass value from the label property-->
          

          显示为:

          <p>{{label.value}}</P>
          

          父组件有一个文本框和一个标签。

          import { Component, bootstrap} from '@angular/core';
          import {Display} from 'display';
          
          @Component({
            selector: 'my-app',
            template: `<p><b>Parent Component:</b><p><input #label (keyup) (change)="handleChange(label.value)">
                  <p>{{label.value}}</P> <display [text]="label"></display></p></p>`,
            directives: [Display]
          })
          
          class MainComponent {
            label: any;
          
            constructor() {
          
            }
          
            handleChange(label){
              this.label = label;
              console.log(this.label);
            }
          
          }
          

          现在也在子组件中显示它:

          @Component({
            selector: 'edit',
            template: `<p><b>Child Component:</b></p>{{text.value}}`
          })
          
          export class Edit {
              @Input() text:any;
          }
          

          Demo



          更新 - 用于 2 向绑定的 ng-model

          虽然Angular2默认是一次性绑定的,但引入ngModelsugar实现2路绑定。例如,您可以这样做:

          <input ngControl="name" [(ngModel)]="name">
          

          这里使用方括号 ([..]) 建议属性绑定和圆括号 ((..)) 用于事件绑定。基本上,当您使用ng-model 时,您启用了两个绑定ngModel 更像是一个事件。在幕后,它创建了一个可观察事件(使用EventEmitter)来跟踪绑定元素中的value 更改并分别更新绑定属性。 例如:-

          包括 formDirectives:

           import {FORM_DIRECTIVES} from '@angular/common';
          

          和形式

             <form (ngSubmit)="onSubmit()" let-f="form">
                <input ngControl="name" [(ngModel)]="name">
                <button>Click me and check console</button>
             </form>
          

          没有形式

            <input  [(ngModel)]="name">
            <button (click)="onSubmit()">Click me and check console</button>
          

          不再需要了 在视图注释中包含 formDirectives 依赖。

          @Component({
            template: .....,
            directives: [FORM_DIRECTIVES]
          })
          

          Demo

          还可以通过创建 ng-model 事件及其工作原理阅读有关 angular2 中双向绑定的 nice write up from Victor Savkin

          【讨论】:

          【解决方案7】:

          还有另一种方法可以欺骗 Angular2 进行双向绑定。不要将属性而是对象传递给组件。如果你通过单向绑定传递一个对象,它的所有属性实际上都是双向绑定的。 它使组件的通用性降低,因为它需要知道对象,但在许多情况下它仍然有用。

          我有一个如下所示的组件:

          import { Component, Input }    from "@angular/core";
          import { NgSwitch, NgSwitchWhen, NgSwitchDefault }    from "@angular/common";
          
          export class Movie
          {
              public Title: string;
              public Rating: number;
              public Seen: boolean;
          }
          
          @Component
          ({
              selector: "hh-image-checkbox",
              template: `
                  <div [ngSwitch]="movie.Seen"> 
                      <div *ngSwitchWhen="true">
                          <img src="/Content/res/CheckTrue.png" (click)="onClick()"> 
                      </div> 
                      <div *ngSwitchDefault> 
                          <img src="/Content/res/CheckFalse.png" (click)="onClick()"> 
                      </div> 
                  </div>
                  `,
              directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault]
          })
          
          export class ImageCheckboxComponent
          {
              @Input() movie: Movie;
          
              public onClick()
              {
                  this.movie.Seen = !this.movie.Seen;
              }
          }
          

          它是这样调用的:

          <hh-image-checkbox [movie]="movie"></hh-image-checkbox>
          

          电影对象本身是单向绑定的,但它的所有属性都可以用于双向绑定。

          【讨论】:

          • 无需导入NgSwitch, NgSwitchWhen, NgSwitchDefault and add them to directives. They are provided globally by PLATFORM_DIRECTIVES`
          【解决方案8】:

          您可以通过附加到输入字段上的事件并更新内部值来做到这一点,如本示例中所做的那样:

          http://plnkr.co/edit/lOFzuWtUMq1hCnrm9tGA?p=preview

          创建一个组件,该组件的内部属性包含标签 this.label 和回调 changeLabel,需要事件对象

          @Component({
            selector: 'app',
            templateUrl: 'bound.html'
          })
          class App {
            label: string;
            constructor() {
              this.label = 'default label'
            }
            changeLabel(event) {
              this.label = event.target.value;
            }
          }
          
          bootstrap(App);
          

          创建您的模板并将回调附加到适当的事件(您可以将其附加到 keypress 事件,但您可能需要超时。为简单起见,我将其附加到 change 事件(这意味着您可能需要关闭输入以查看更新)。

          <label for="myinput">{{label}}</label>
          <input id="myinput" type="text"/>
          <p></p>You can change the label above by typing something below</p>
          <label for="labeltext">New Label Text</label>
          <input type="text" id="labeltext" (change)="changeLabel($event)"/>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-08-20
            • 1970-01-01
            • 2017-05-10
            • 2017-06-19
            • 1970-01-01
            • 1970-01-01
            • 2013-02-24
            • 1970-01-01
            相关资源
            最近更新 更多