跳至正文
首页 » 博客 » Angular Component Data Flows Using @Output and EventEmitter

Angular Component Data Flows Using @Output and EventEmitter

与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提供了:

  1. @ Input装饰器
  1. @ 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;

这个countChangeemit (this.count );

}

}

现在,我们正在执行以下任务,在ChildComponent

  1. 已创建的实例EventEmitter被称为countChange,它将被发射到按钮的click事件上的父组件。
  1. 创建了一个函数命名为updateCount()。这个函数叫做on按钮的click事件,以及在函数内部事件countChange是发射的。
  1. 发射时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类:

  1. 在模板中使用 <app-child>。
  1. <app-child> 元素,使用事件绑定来使用countChange事件。
  1. 正在调用changeCount上的函数countChange事件。
  1. 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>

使用此代码,产品呈现在表中,如下图所示:

现在让我们说我们要添加一个新列与一个按钮和输入框,如下图所示:

我们的要求如下:

  1. 如果的价值库存超过10,然后按钮颜色应为绿色。
  1. 如果的价值库存小于10,然后按钮颜色应为红色。
  1. The user可以输入一个数字输入框,将添加到那个特定的股票价值。
  1. The color的按钮应更新的基础上已更改的值产品库存。

为了完成这个任务,让我们创建一个名为StockStausComponent本质上,在的模板中StockStatusComponent,有一个但是吨和一个数字输入框。在StockStatusComponent:

  1. 我们需要阅读的价值库存传递自AppComponnet。对于这个,我们需要使用 @ Input
  1. 我们需要发射一个事件所以中的一个函数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探索在班级上方一行一行。

  1. 第一行我们are导入所需的一切:@ 输入,@ 输出等。
  1. 在模板中,有一个数字输入框是已绑定updatedStockValue属性使用[(ngModel)]我们需要传递这个值一个事件到AppComponent
  1. 在模板中,有一个按钮。开按钮的click事件,则会向AppComponent
  1. 我们需要设置按钮的颜色的基础产品库存价值。所以,我们必须使用属性绑定到set按钮的背景。The v的值color属性在类中更新。
  1. 我们正在创建两个 @输入 () 装饰属性库存productId因为这两个属性的值将从AppComponent
  1. 我们正在创建一个事件被称为stockValueChange。此事件将被发送到AppComponent点击按钮。
  1. 股票价值变化函数,我们正在发射stockValueChange事件,也传递要更新的产品id和要添加到产品库存值中的值。
  1. 我们正在更新中颜色属性的值性腺变化() 生命周期挂钩,因为每次股票价值在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