在父子指令及元件之間共享資料
Sharing data between child and parent directives and components
Angular 中的一個常見模式就是在父元件和一個或多個子元件之間共享資料。你可以用 @Input()
和 @Output()
來實現這個模式。
A common pattern in Angular is sharing data between a parent component and one or more child components. You can implement this pattern by using the @Input()
and @Output()
directives.
考慮以下層次結構:
Consider the following hierarchy:
<parent-component>
<child-component></child-component>
</parent-component>
<parent-component>
充當了 <child-component>
的上下文。
The <parent-component>
serves as the context for the <child-component>
.
@Input()
和 @Output()
為子元件提供了一種與其父元件通訊的方法。 @Input()
允許父元件更新子元件中的資料。相反,@Output()
允許子元件向父元件傳送資料。
@Input()
and @Output()
give a child component a way to communicate with its parent component. @Input()
allows a parent component to update data in the child component. Conversely, @Output()
allows the child to send data to a parent component.
把資料傳送到子元件
Sending data to a child component
子元件或指令中的 @Input()
裝飾器表示該屬性可以從其父元件中獲取值。
The @Input()
decorator in a child component or directive signifies that the property can receive its value from its parent component.
要使用 @Input()
,就必須對父元件和子元件進行配置。
To use @Input()
, you must configure the parent and child.
配置子元件
Configuring the child component
要使用 @Input()
裝飾器,首先要匯入 Input
,然後用 @Input()
裝飾該屬性,如下例所示。
To use the @Input()
decorator in a child component class, first import Input
and then decorate the property with @Input()
, as in the following example.
import { Component, Input } from '@angular/core'; // First, import Input
export class ItemDetailComponent {
@Input() item = ''; // decorate the property with @Input()
}
在這個例子中, @Input()
會修飾屬性 item
,它的型別為 string
,但 @Input()
屬性可以是任意型別,比如 number
、string
、boolean
或 object
。item
的值來自父元件。
In this case, @Input()
decorates the property item
, which has a type of string
, however, @Input()
properties can have any type, such as number
, string
, boolean
, or object
. The value for item
comes from the parent component.
接下來,在子元件範本中新增以下內容:
Next, in the child component template, add the following:
<p>
Today's item: {{item}}
</p>
配置父元件
Configuring the parent component
下一步是在父元件的範本中繫結該屬性。在這個例子中,父元件範本是 app.component.html
。
The next step is to bind the property in the parent component's template. In this example, the parent component template is app.component.html
.
使用子元件的 selector (
<app-item-detail>
) 作為父元件範本中的指令。Use the child's selector, here
<app-item-detail>
, as a directive within the parent component template.使用屬性繫結把子元件的
item
屬性繫結到父元件的currentItem
屬性上。Use property binding to bind the
item
property in the child to thecurrentItem
property of the parent.
<app-item-detail [item]="currentItem"></app-item-detail>
在父元件類別中,為
currentItem
指定一個值:In the parent component class, designate a value for
currentItem
:
export class AppComponent {
currentItem = 'Television';
}
透過 @Input()
,Angular 把 currentItem
的值傳給子元件,以便 item
渲染為 Television
。
With @Input()
, Angular passes the value for currentItem
to the child so that item
renders as Television
.
下圖展示了這種結構:
The following diagram shows this structure:
方括號 []
中的目標就是子元件中用 @Input()
裝飾的那個屬性。繫結源(等號的右邊部分)則是父元件傳給內嵌元件的資料。
The target in the square brackets, []
, is the property you decorate with @Input()
in the child component. The binding source, the part to the right of the equal sign, is the data that the parent component passes to the nested component.
監視 @Input()
的變更
Watching for @Input()
changes
要想監視 @Input()
屬性的變化,你可以使用 Angular 的生命週期鉤子OnChanges
。更多詳情和範例,請參閱生命週期鉤子 一章的 OnChanges
部分。
To watch for changes on an @Input()
property, you can use OnChanges
, one of Angular's lifecycle hooks. See the OnChanges
section of the Lifecycle Hooks guide for more details and examples.
把資料傳送到父元件
Sending data to a parent component
子元件或指令中的 @Output()
裝飾器允許資料從子元件傳給父元件。
The @Output()
decorator in a child component or directive allows data to flow from the child to the parent.
@Output()
在子元件中標記了一個屬性,作為資料從子元件傳遞到父元件的途徑。
@Output()
marks a property in a child component as a doorway through which data can travel from the child to the parent.
子元件使用 @Output()
屬性來引發事件,以通知父元件這一變化。為了引發事件, @Output()
必須是 EventEmitter
型別,它是 @angular/core
中用來發出自定義事件的類別。
The child component uses the @Output()
property to raise an event to notify the parent of the change. To raise an event, an @Output()
must have the type of EventEmitter
, which is a class in @angular/core
that you use to emit custom events.
下面的例子給出瞭如何在元件中設定 @Output()
,來把資料從 HTML 的 <input>
推送到父元件的陣列中。
The following example shows how to set up an @Output()
in a child component that pushes data from an HTML <input>
to an array in the parent component.
要使用 @Output()
,就必須配置父元件和子元件。
To use @Output()
, you must configure the parent and child.
配置子元件
Configuring the child component
下面的例子中有一個 <input>
,使用者可以輸入一個值,然後點選一個引發事件 <button>
然後, EventEmitter
資料中繼到父元件。
The following example features an <input>
where a user can enter a value and click a <button>
that raises an event. The EventEmitter
then relays the data to the parent component.
在子元件類別中匯入
Output
和EventEmitter
Import
Output
andEventEmitter
in the child component class:import { Output, EventEmitter } from '@angular/core';
在元件類別中,用
@Output()
裝飾一個屬性。下面的例子中newItemEvent
這個@Output()
的型別為EventEmitter
,這意味著它是一個事件。In the component class, decorate a property with
@Output()
. The following examplenewItemEvent
@Output()
has a type ofEventEmitter
, which means it's an event.src/app/item-output/item-output.component.ts @Output() newItemEvent = new EventEmitter<string>();
上述宣告中的差異點如下:
The different parts of the above declaration are as follows:
@Output()
- 一個裝飾器函式,它把該屬性標記為資料從子元件進入父元件的一種途徑@Output()
—a decorator function marking the property as a way for data to go from the child to the parentnewItemEvent
- 這個@Output()
的名字newItemEvent
—the name of the@Output()
EventEmitter<string>
- 這個@Output()
的型別EventEmitter<string>
—the@Output()
's typenew EventEmitter<string>()
- 使用 Angular 來建立一個新的事件發射器,它發出的資料是string
型別的。new EventEmitter<string>()
—tells Angular to create a new event emitter and that the data it emits is of type string.關於
EventEmitter
的詳細資訊,請參閱 EventEmitter API 文件。For more information on
EventEmitter
, see the EventEmitter API documentation.
在同一個元件類別中建立一個
addNewItem()
方法:Create an
addNewItem()
method in the same component class:src/app/item-output/item-output.component.ts export class ItemOutputComponent { @Output() newItemEvent = new EventEmitter<string>(); addNewItem(value: string) { this.newItemEvent.emit(value); } }
addNewItem()
函式使用newItemEvent
這個@Output()
來引發一個事件,該事件帶有使用者輸入到<input>
中的值。The
addNewItem()
function uses the@Output()
,newItemEvent
, to raise an event with the value the user types into the<input>
.
配置子元件的範本
Configuring the child's template
子元件的範本有兩個控制元件。第一個是帶有範本參考變數 #newItem
的 <input>
,使用者可在其中輸入條目名稱。 #newItem
變數的 value
屬性儲存了使用者輸入到 <input>
中的值。
The child's template has two controls. The first is an HTML <input>
with a template reference variable , #newItem
, where the user types in an item name. The value
property of the #newItem
variable stores what the user types into the <input>
.
<label for="item-input">Add an item:</label>
<input type="text" id="item-input" #newItem>
<button (click)="addNewItem(newItem.value)">Add to parent's list</button>
第二個元素是帶有 click
事件繫結 的 <button>
元素。
The second element is a <button>
with a click
event binding.
(click)
事件繫結到了子元件類別中 addNewItem()
方法。addNewItem()
方法接受一個 #newItem.value
屬性的值作為引數。
The (click)
event is bound to the addNewItem()
method in the child component class. The addNewItem()
method takes as its argument the value of the #newItem.value
property.
配置父元件
Configuring the parent component
此範例中的 AppComponent
有一個 items
列表,以及一個向陣列中新增更多條目的方法。
The AppComponent
in this example features a list of items
in an array and a method for adding more items to the array.
export class AppComponent {
items = ['item1', 'item2', 'item3', 'item4'];
addItem(newItem: string) {
this.items.push(newItem);
}
}
addItem()
方法接受一個字串形式的引數,然後把該字串新增到 items
陣列中。
The addItem()
method takes an argument in the form of a string and then adds that string to the items
array.
配置父元件的範本
Configuring the parent's template
在父範本中,把父元件的方法繫結到子元件的事件上。
In the parent's template, bind the parent's method to the child's event.
把子元件選擇器(
<app-item-output>
)放在父元件的範本app.component.html
中。Put the child selector, here
<app-item-output>
, within the parent component's template,app.component.html
.src/app/app.component.html <app-item-output (newItemEvent)="addItem($event)"></app-item-output>
事件繫結
(newItemEvent)='addItem($event)'
會把子元件中的newItemEvent
事件連線到父元件的addItem()
方法。The event binding,
(newItemEvent)='addItem($event)'
, connects the event in the child,newItemEvent
, to the method in the parent,addItem()
.$event
中包含使用者在子元件範本上的<input>
中鍵入的資料。The
$event
contains the data that the user types into the<input>
in the child template UI.要了解
@Output()
的工作方式,你可以把以下內容新增到父元件的範本中:To see the
@Output()
working, you can add the following to the parent's template:<ul> <li *ngFor="let item of items">{{item}}</li> </ul>
*ngFor
會迭代items
陣列中的條目。當你在子元件的<input>
中輸入一個值並單擊該按鈕時,子元件就會發出該事件,而父元件的addItem()
方法會把這個值追加到其items
陣列中,並且列表中會渲染出這個新條目。The
*ngFor
iterates over the items in theitems
array. When you enter a value in the child's<input>
and click the button, the child emits the event and the parent'saddItem()
method pushes the value to theitems
array and new item renders in the list.
同時使用 @Input()
和 @Output()
Using @Input()
and @Output()
together
你可以在同一個子元件上使用 @Input()
和 @Output()
,範例如下:
You can use @Input()
and @Output()
on the same child component as follows:
<app-input-output [item]="currentItem" (deleteRequest)="crossOffItem($event)"></app-input-output>
目標 item
是子元件類別中的一個 @Input()
屬性,它會從父元件的 currentItem
屬性中獲取它的值。當你單擊“刪除”時,子元件就會引發一個事件 deleteRequest
,它會作為父元件中 crossOffItem()
方法的引數。
The target, item
, which is an @Input()
property in the child component class, receives its value from the parent's property, currentItem
. When you click delete, the child component raises an event, deleteRequest
, which is the argument for the parent's crossOffItem()
method.
下圖展示了子元件 <app-input-output>
中 @Input()
和 @Output()
的各個部分。
The following diagram shows the different parts of the @Input()
and @Output()
on the <app-input-output>
child component.
這裡的子選擇器是 <app-input-output>
,它所帶的 item
和 deleteRequest
是子元件類別中的 @Input()
和 @Output()
屬性。而 currentItem
屬性和 crossOffItem()
方法都位於父元件類別中。
The child selector is <app-input-output>
with item
and deleteRequest
being @Input()
and @Output()
properties in the child component class. The property currentItem
and the method crossOffItem()
are both in the parent component class.
要想用“盒子裡的香蕉” [()]
語法來組合屬性和事件繫結,參閱雙向繫結。
To combine property and event bindings using the banana-in-a-box syntax, [()]
, see Two-way Binding.