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

时间:2016-03-27 11:54:04

标签: angular

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

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

然后我获得了使用CoreComponent的{​​{1}}以及FormInputComponent类中的public user

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: '' } } 可以更新具有新值的模型:

CoreComponent

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); } } 的模板使用两个CoreComponent,并传递FormInputComponentuser.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> 模板:

FormInputComponent

现在的问题是,我只能看到<div> <label attr.for="{{name}}">{{label}}</label> <input [(ngModel)]="model" type="{{type}}" placeholder="{{placeholder}}" alt="{{alt}}" id="{{name}}"> </div> <pre>{{model}}</pre> 模板中pre元素的更改,但父级FormInputComponent&#39; {{1}元素保持不变。

我看了this question这是我想要实现的目标,但不完全是因为使用服务只是在层次结构中返回一个值似乎有点过分而且有点混乱如果你有多个{{ 1}}在同一页面上。

所以我的问题很简单,如何将模型传递给CoreComponent,并在值发生变化时让它返回一个新值,以便pre中的FormInputComponent自动更改?< / p>

4 个答案:

答案 0 :(得分:26)

为了能够在使用组件时使用双向绑定短路,您需要将输出属性重新读取到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>

答案 1 :(得分:19)

作为补充:使用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方法中做到这一点非常方便,而且当我在视图中直接绑定它时,不必费心。

答案 2 :(得分:6)

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

使用emit()代替next()(已弃用),仅在emit(newValue)的值更改时调用model。你很可能在FormInputComponent模板中想要这样的东西:

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

然后在FormInputComponent逻辑中:

onChanges(newValue) {
  this.model = newValue;
  this.changeModel.emit(newValue);
}

答案 3 :(得分:0)

我发现其他答案有些混乱,因此我将所有内容归结为我认为是一个非常简单的答案,并附带一个Stack Blitz示例。

此示例仅需要2个简单组件,即app.component和test.component。真正的魔力只需要在输出装饰器的名称后附加“更改”即可。只需使用确切的名称作为@Input装饰器,然后在其末尾添加“ Change”即可。在此示例中,@ Input名称为“ testVal”,@ Output名称为“ testValChange”,对于外行来说,它是Angular语法糖或魔术师:-)。

以下是完整的app.component.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";

}

以下是完整的test.component文件,

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++;
  }
}

干杯!