与AngularJS不同,Angular没有双向数据绑定。当我说,角n不有双向数据绑定,它并不意味着你不能做到这一点。没有双向数据绑定的支持,任何现代web框架都无法存在。Angular提供此函数使用的ngModel指令。要使用它,您需要导入FormsModule和然后你可以用各种方式使用它,例如:
- ngModel
- [ngModel]
- [( ngModel )]
You may奇迹为什么Angular没有像AngularJS这样的双向数据绑定。AngularJS一次实施ed二-使用摘要循环、脏检查算法进行数据绑定的方式,和其他,而这些方法有他们自己的问题。在这文章,我们威尔专注于AngularJS双向数据绑定的问题所以,你明白为什么它是在不同的角度处理。
回到Angular,双向数据绑定可以描述为如下所示:
方括号s代表属性绑定,小括号表示事件绑定,而的两者的组合表示双向数据绑定。双向数据绑定的语法也称为banana in box语法。在此处了解有关数据绑定的更多信息。
现在,您对Angular中的不同类型的绑定有了一些了解; 让的了解数据如何在角度组件。数据可能是的原始类型es、数组、对象或事件。为了在组件之间流动数据,Angular提供了:
- @ Input装饰器
- @ Output装饰器
这两个装饰器都是 @ angular/ core的一部分。
@输入 () 装饰工将类字段标记为输入属性并提供配置元数据。它声明了一个数据绑定输入属性,Angular会在更改检测期间自动更新该属性。
@ Output decorator将类字段标记为输出属性,并提供配置的元数据。它声明了一个数据绑定输出属性,Angular会自动更新更改检测。
这两个装饰器用于在组件之间流动数据。请记住,除了这两个装饰器之外,您还可以使用Angular服务在的组件。如果必须将数据传递到组件中,请使用 @ Input装饰器,如果必须从组件发出数据,请使用 @ Output装饰器。
Both装饰器s工作当组件之间相互关联时。例如,如果您正在使用名为ChildComponent在另一个名为AppComponent,它们是相互关联的。Youcan请参见这在的下面的图像,和任何ChildComponent用 @ Input装饰器装饰的属性可以从AppComponent。
它更好地理解 ,考虑ChildComponent如下:
导入{组件,OnInit,输入}从‘@ angular/core’;
@ 组件 ({
选择器: 的 ‘app-child’,
模板: ‘<p>count = {{count }}< /p>
‘
})
导出类ChildComponent实现了OnInit {
() { } 构造函数
@ Input () count: number;
ngOnInit () {
}
}
如果你仔细观察在上面的代码片段,我们使用 @输入 () 带有count属性的装饰器,这意味着count属性的值将从ChildComponent。我们可以使用ChildComponent内部AppComponent并且可以使用属性绑定来传递count属性的值,如下面的清单所示:
从 “@ angular/core” 导入 {Component};
@ 组件 ({
选择器: ‘app-root’,
模板: ‘<h2 >{{ title }}</h2>
<app-child [count]= ‘count’></app-child>
‘
})
{导出类AppComponent
计数 =; 9
}
我们正在使用ChildComponent内部AppComponent并使用属性绑定在传递数据ChildComponent。右侧现在正在单向传递数据定向流到ChildComponent。记住任何时间的a的值n输入–绑定属性更新,Angular运行更改检测器。但是,您可以配置更改检测器应如何在 @ Input装饰器上运行。此外,每次 @ input decorator属性更新,角运行性腺变化() 生命周期挂钩,因此您可以读取的输入的更新值–绑定属性性腺变化() 生命周期挂钩。
现在那我们知道何w将数据从父组件传递到子组件,让‘s开关我们关注如何将数据和事件从子组件发送到父组件。要从组件发出数据和事件,我们需要
- 使用 @ output装饰器装饰属性。由做,此属性成为出站数据属性。
- 创建的实例EventEmitter并用 @ Output装饰器装饰它。
注意在下面的图像 ,数据或事件去一个组件使用 @ Output装饰。
之前我解释如何EventEmitter操作详细,请评审下面的代码示例。修改ChildComponent带有一个按钮,如下所示:
导入{组件,OnInit,输入}从‘@ angular/core’;
@ 组件 ({
选择器: “app-child”,
template: ‘ <p>count = {{count }}</p>
<button (click)= ‘updateCount()’> 更新计数 </button>
‘
})
导出类ChildComponent实现了OnInit {
() { } 构造函数
@ Input () count: number;
ngOnInit () {
}
updateCount () {
此.count = 1此.count;
}
}
当您单击ChildComponent,它更新计数值。超级简单。到目前为止,click事件在ChildComponent本身。
N哦,让我们调整需求有点。如果您要执行的函数AppComponent的单击事件a里面的按钮ChildComponent?
为此,您必须发出ChildComponent的按钮单击事件。使用event emit,您还可以将数据从ChildComponent发送出去。让 ‘的修改ChildComponent来发出数据和事件以捕获在AppComponent中。
导入{组件,OnInit,输入,输出,EventEmitter}从‘@ angular/core’;
@ 组件 ({
的选择器: “app-child”,
template: ‘ <p>count = {{count }}</p>\
<button (click)= ‘updateCount()’> 更新计数 </button>
‘
})
导出类ChildComponent实现了OnInit {
() { } 构造函数
@ Input () count: number;
@ Output () countChange = EventEmitter新 ();
ngOnInit () {
}
updateCount () {
这个。这个计数 =。计数1;
这个。countChange。emit (this.count );
}
}
现在,我们正在执行以下任务,在的ChildComponent
- 已创建的实例EventEmitter被称为countChange,它将被发射到的按钮的click事件上的父组件。
- 创建了一个函数命名为updateCount()。这个函数叫做on按钮的click事件,以及在函数内部事件countChange是发射的。
- 发射时countChange事件,值为count属性也从组件发出。
在我们前进之前,让我们了解EventEmitter。它在指令和组件中用于同步或异步发出自定义事件。任何处理程序都可以处理通过订阅这些事件一个的实例EventEmitter类。它不同于a正常的HTML事件,因为它使用RxJS可观察到的,这样的处理程序可以订阅事件。
如果你看看实现的EventEmitter的类,它扩展主题类。
自EventEmitter类扩展RxJs主题类,这意味着它是可观察到的,并且可以多播对许多观察者来说s。它不是的与相同aDOM事件,哪个?can不是muticasted并观察到。
在AppComponent,您可以处理从发出的事件ChildComponent如图所示的下面的代码清单:
从 “@ angular/core” 导入 {Component};
@ 组件 ({
的选择器: ‘app-root’,
模板 ‘<h2 >{{ title }}</h2>
<app-child [count]= ‘count’ (countChange)= changeCount($ event)></app-child>
‘
})
AppComponent {导出类
= 计数9;
变更计数 (数据) {
控制台。日志 (数据 );
}
}
现在,我们正在执行以下任务在AppComponent的类:
- 在模板中使用 <app-child>。
- 在的<app-child> 元素,使用事件绑定来使用的countChange事件。
- 正在调用的changeCount上的函数countChange事件。
- 在的changeCount功能,打印的的价值的计数传递自的ChildComponent。
正如你所看到的,的功能AppComponent上放置的按钮的click事件调用的ChildComponent。这可以用@ 输出和EventEmitter。现在数据在组件之间流动s使用的@输入 () 和 @ Output() 装饰器s。
如您所见,我们在两个组件之间创建了双向数据绑定。如果你看一下代码,它是a属性绑定和事件绑定的组合。
一个实时示例
让‘s拿一个真正的–时间示例以查找 @ Output和EventEmitter更有用。考虑一下AppComponent正在渲染a以表格形式的产品列表如图所示下面:
为了创建上面的产品表 ,我们有一个非常简单的AppComponent类,其中只有一个函数: 返回一个产品列表。
AppComponent导出类实现OnInit {
产品 = []; 已
title = “ 产品”;
ngOnInit () {
这。产品=这。getProducts();
}
(getProducts) {
返回 [
{‘id’: ‘1’,’title’: ‘螺丝驱动’,’价格’: 400,‘stock’: 11 },
{‘id’: ‘2’,’title’: ‘nutvol’,’price’: 200,‘stock’ 5 : },
{‘id’: ‘3’, ‘title’: ‘Resistor’, ‘price’:78,‘库存’:45},
{‘id’: ‘4’,’title’: ‘Tractor’,’price’:,20000,‘stock’: 1 },
{‘id’: ‘5’,’title’: ‘Roller’,’price’: 62,‘stock’: 15 },
];
}
}
在th中engOnInit生命周期钩子,我们正在调用的getPrdoducts() 功能和分配的返回的data至的产品变量所以它可以使用d在模板上。那里,我们正在使用的*ngFor指令要迭代通过的阵列和显示产品。请参阅下面的代码:
class = <div “container” >
<br/>
<h1类=“文本中心”>{{标题}}</h1>
<table class = “table” >
<thead>
<th> Id </th>
<th> 标题 </th>
<th> 价格 </th>
<th> 库存 </th>
</thead>
<tbody>
<tr * ngFor = “let p of products” >
<td>{{p.id}}</td>
<td> {{ p.title }} </td>
<td> {{ p.price }} </td>
<td> {{ 库存 }} </td>
</tr>
</tbody>
</table>
</div>
使用此代码, 将产品呈现在表中,如下图所示:
现在,让我们说,我们要添加一个新列与,一个按钮和输入框,如下图所示:
我们的要求如下:
- 如果的的价值库存超过10,然后的按钮颜色应为绿色。
- 如果的的价值库存小于10,然后的按钮颜色应为红色。
- The user可以输入一个数字输入框,将添加到那个特定的股票价值。
- The color的的按钮应更新的基础上的已更改的值的产品库存。
为了完成这个任务,让我们创建一个名为StockStausComponent。本质上,在的模板中StockStatusComponent,有一个但是吨和一个数字输入框。在StockStatusComponent:
- 我们需要阅读的的价值库存传递自AppComponnet。对于这个,我们需要使用 @ Input
- 我们需要发射一个事件所以中的一个函数AppComponent可以调用的点击的StockStatusComponent按钮。为此,我们需要使用 @ Output和EventEmitter。
考虑下面的代码:
stockstatus.com部件。ts
导入{组件,输入,EventEmitter,输出,OnChanges}从‘@ angular/core’;
@ {组件 (
选择器: ‘app-stock-status ‘,
template: ‘<input type = ‘number’ [(ngModel)]= ‘updatedstockvalue’/> <button class = ‘btn btn-primary’
[style.background]= ‘颜色’
(单击) = “stockValueChanged()”> 更改库存值 </按钮> ‘
})
导出类StockStatusComponent实现OnChanges {
@ Input() stock: 编号;
@ Input() productId: number;
@输出 ()stockValueChange=新建EventEmitter();
颜色 = ”;
updatedstockvalue: number;
stockValueChanged () {
这。stockValueChange.emit({ id:这。productId,updatdstockvalue:这。updatedstockvalue});
这。updatedstockvalue=null;
}
ngOnChanges () {
如果 (此 > > 10 .stock) {
这。颜色=“绿色”;
} else {
这。颜色=“红”;
}
}
}
Let’s探索的在班级上方一行一行。
- 在的第一行我们are导入所需的一切:@ 输入,@ 输出等。
- 在模板中,有一个数字输入框是已绑定至的updatedStockValue属性使用[(ngModel)]。我们需要传递这个值一个事件到AppComponent。
- 在模板中,有一个按钮。开的按钮的click事件,则会向AppComponent。
- 我们需要设置的按钮的颜色的的基础的产品库存价值。所以,我们必须使用属性绑定到set按钮的背景。The v的值的color属性在类中更新。
- 我们正在创建两个 @输入 () 装饰属性–库存和productId–因为这两个属性的值将从AppComponent。
- 我们正在创建一个事件被称为stockValueChange。此事件将被发送到AppComponent点击按钮。
- 在股票价值变化函数,我们正在发射的stockValueChange事件,也传递的要更新的产品id和的要添加到产品库存值中的值。
- 我们正在更新的中颜色属性的值的性腺变化() 生命周期挂钩,因为每次的股票价值在AppComponent,the的价值的应更新color属性。
在这里,我们使用的@ Input decorator从中读取数据AppComponent类,这发生s要成为的这种情况下的父类。To将数据从的父组件类到的child组件类,使用 @ Input装饰器。
此外,我们是将 @ Output与EventEmitterto发出事件到AppComponent。所以要发射一个事件来自的子组件类到的父组件类,使用EventEmitter与 @输出 () 装饰师。
因此,StockStatusComponent正在使用 @ Input和 @ Output读取数据从AppComponent并发出事件到AppComponent。
修改AppComponent以使用StockStatusComponent
让我们先修改一下的模板。在模板中,添加一个新的表列。列内,the使用 <app-stock-status> 组件。
<div class = “container” >
<br/>
<h1类 = “text-center” > > {{title} }} </h1>
<table class = “table” >
<thead>
Id < th > </th>
标题 < th > </th>
价格 < th > </th>
库存 < th > </th>
</thead>
<tbody>
<tr * ngFor = > “let p of products”
<td> {{p.id }} </td>
<td> {{ p.title }} </td>
<td> {{ p.price }} </td>
<td> {{ 库存 }} </td>
<td><app-stock-status[productId] =‘p.id’[库存] =‘p.库存’(stockValueChange) =‘changeStockValue($ event)’></app-stock-status></td>
</tr>
</tbody>
</table>
</div>
我们正在传递的值到productId和库存使用属性绑定 (记住,这两个属性用 @ 装饰输入 () 在StockStatusComponent) 和使用事件绑定来处理stockValueChange事件(记住,此活动用 @ O装饰utput() 在StockStatusComponent)。
接下来,我们需要添加changeStockValue功能在AppComponent。将以下代码添加到AppComponent班级:
productToUpdate: 任何;
changeStockValue (p) {
这。productToUpdate=这。产品.查找(这。findProducts, [p.id]);
这。productToUpdate.stock=这。productToUpdate.stockp.updatdstockvalue;
}
findProducts (p) {
返回p.id === 这个0 [];
}
在函数中,我们使用的JavaScriptArray.prototype.find方法来查找产品a匹配productId然后更新的库存计数的的匹配ed产品。当您运行应用程序,你会获取以下输出:
W当您在数字框中输入数字并单击按钮时,您将执行m子组件中的任务,用于更新中的操作值的父组件。此外,在的的基础的父组件值,的正在子组件中更改样式。所有这一切都可以使用角@ Input,@ Output,和EventEmitter。
请继续关注未来的文章,我们将更深入地了解Angular的其他功能!
</p