代码之家  ›  专栏  ›  技术社区  ›  Chrillewoodz

如何在angular 2中的组件之间使用双向数据绑定?

  •  22
  • Chrillewoodz  · 技术社区  · 10 年前

    首先,我创建了一个 User 类别:

    export class User {
      name: string;
      email: string;
    }
    

    然后我得到了我的 CoreComponent 它使用 FormInputComponent 以及创建 public user 来自 使用者 类别:

    import {Component} from 'angular2/core';
    import {FormInputComponent} from '../form-controls/form-input/form-input.component';
    import {User} from '../core/user';
    
    @Component({
      selector: 'core-app',
      templateUrl: './app/assets/scripts/modules/core/core.component.html',
      styleUrls: ['./app/assets/scripts/modules/core/core.component.css'],
      directives: [FormInputComponent]
    })
    
    export class CoreComponent {
      public user: User = {
        name: '',
        email: ''
      }
    }
    

    然后我创建了一个输入组件,这是一个可重用的输入组件,它将模型值作为输入,当进行更改时,导出新值,以便 核心组件 可以使用新值更新模型:

    import {Component, Input, Output, EventEmitter, DoCheck} from 'angular2/core';
    
    @Component({
      selector: 'form-input',
      templateUrl: './app/assets/scripts/modules/form-controls/form-input/form-input.component.html',
      styleUrls: ['./app/assets/scripts/modules/form-controls/form-input/form-input.component.css'],
      inputs: [
        'model',
        'type',
        'alt',
        'placeholder',
        'name',
        'label'
      ]
    })
    
    export class FormInputComponent implements DoCheck {
      @Input() model: string;
      @Output() modelExport: EventEmitter = new EventEmitter();
    
      ngDoCheck() {
        this.modelExport.next(this.model);
      }
    }
    

    这个 核心组件 的模板使用了两个 表单输入组件 s和传球 user.name 和 user.email 作为它们的输入:

    <form-input [model]="user.name" type="text" name="test" placeholder="This is a test" alt="A test input" label="Name"></form-input>
    <form-input [model]="user.email" type="email" name="test" placeholder="This is a test" alt="A test input" label="Email"></form-input>
    <pre>{{user.name}}</pre>
    

    这个 表单输入组件 模板:

    <div>
      <label attr.for="{{name}}">{{label}}</label>
      <input [(ngModel)]="model" type="{{type}}" placeholder="{{placeholder}}" alt="{{alt}}" id="{{name}}">
    </div>
    <pre>{{model}}</pre>
    

    现在的问题是,我只能看到 pre 位于 表单输入组件 模板, 核心组件 的 之前 元素保持不变。

    我看着 this question 这正是我想要达到的目标,但并不完全如此,因为使用一个服务来向上返回一个值,如果你有多个 表单输入组件 s在同一页上。

    所以我的问题很简单,我如何将模型传递给 表单输入组件 并让它在值发生变化时返回一个新值 公共用户 在里面 核心组件 是否自动更改?

    5 回复  |  直到 9 年前
        1
  •  33
  •   Thierry Templier    10 年前

    要在使用组件时使用双向绑定short,您需要将输出属性读入modelChange:

    export class FormInputComponent implements DoCheck {
      @Input() model: string;
      @Output() modelChange: EventEmitter = new EventEmitter();
    
      ngDoCheck() {
        this.modelChange.next(this.model);
      }
    }
    

    这样使用它:

    <form-input [(model)]="user.name" type="text" name="test" placeholder="This is a test" alt="A test input" label="Name"></form-input>
    <form-input [(model)]="user.email" type="email" name="test" placeholder="This is a test" alt="A test input" label="Email"></form-input>
    <pre>{{user.name}}</pre>
    
        2
  •  27
  •   Mario Eis    10 年前

    另外:使用ngDoCheck发出模型更改将严重影响性能,因为每次检查周期都会发出新值,无论是否更改。这真的很常见!(试试console.log!)

    因此,我想做的是这样做,以获得类似的便利,但没有副作用:

    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方法中轻松地完成这一操作非常方便,并且当我直接在视图中绑定它时不必费心。

        3
  •  8
  •   Mark Rajcok    10 年前

    这太长了,不能作为对蒂埃里回答的评论。。。

    使用 emit() 而不是 next() (已弃用),并且仅调用 emit(newValue) 当 model 变化。您很可能希望在FormInputComponent模板中包含这样的内容:

    <input [ngModel]="model" (ngModelChange)="onChanges($event)">
    

    然后在FormInputComponent逻辑中:

    onChanges(newValue) {
      this.model = newValue;
      this.changeModel.emit(newValue);
    }
    
        4
  •  3
  •   user3777549    7 年前

    我发现其他的答案有点令人困惑,所以我把一切都归结为一个我认为非常简单的答案 Stack Blitz 实例

    这个例子只需要两个简单的组件,app。组件&test.com组件。真正的魔法只需要在Output修饰符的名称后面加上“Change”。只需使用确切的名称作为@Input装饰符,并在其末尾添加“Change”即可。在本例中,@Input名称为“testVal”,@Output名称为”testValChange“,这是Angular语法糖,或magic:-)。

    以下是完整的应用程序组件。ts文件,

    import { Component, Input } from "@angular/core";
    
    @Component({
      selector: "my-app",
      template: `
    
      {{testVal}} <-- this value is printed by app.component
    
      <test-component [(testVal)]="testVal"></test-component>
    
      `
    })
    export class AppComponent {
      @Input() testVal = "My Greeting";
    
    }
    

    下面是完整的测试。组件文件,

    import { Component, Input, Output, EventEmitter } from "@angular/core";
    
    @Component({
      selector: "test-component",
      template: `
      <br /><br />
      <input type="button" (click)="hi()" value="update greeting" /> <-- this button in test.component updates the greeting above using two way binding.
      `
    })
    export class TestComponent {
      @Input() testVal;
      @Output() testValChange = new EventEmitter<string>();
      increment = 0;
    
      hi(){
        this.testVal = 'Hey There!';
        this.testValChange.emit(this.testVal + String(this.increment));
        this.increment++;
      }
    }
    

    干杯

        5
  •  0
  •   Vortilion    4 年前

    现在有一个类似的问题,但有一个额外的层:一个组件,它包含一个传递数据对象的子组件,它还包含另一个子组件,该子组件具有一个输入字段,它将相同的数据对象传递给它。我想编辑输入字段,并将数据备份2层传递给父组件。由于某种原因无法实现。。。

    我添加了一个stackblitz: https://stackblitz.com/edit/angular-8oh2fm

    推荐文章