填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫Home

在父子指令及元件之間共享資料

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.

本章包含程式碼片段的可工作實例參閱現場演練 / 下載範例

See the現場演練 / 下載範例for a working example containing the code snippets in this guide.

考慮以下層次結構:

Consider the following hierarchy:

<parent-component> <child-component></child-component> </parent-component>
      
      <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: string; // decorate the property with @Input() }
src/app/item-detail/item-detail.component.ts
      
      import { Component, Input } from '@angular/core'; // First, import Input
export class ItemDetailComponent {
  @Input() item: string; // decorate the property with @Input()
}
    

在這個例子中, @Input() 會修飾屬性 item,它的型別為 string,但 @Input() 屬性可以是任意型別,比如 numberstringbooleanobjectitem 的值來自父元件。

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>
src/app/item-detail/item-detail.component.html
      
      <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.

  1. 使用子元件的 selector (<app-item-detail>) 作為父元件範本中的指令。

    Use the child's selector, here <app-item-detail>, as a directive within the parent component template.

  2. 使用屬性繫結把子元件的 item 屬性繫結到父元件的 currentItem 屬性上。

    Use property binding to bind the item property in the child to the currentItem property of the parent.

<app-item-detail [item]="currentItem"></app-item-detail>
src/app/app.component.html
      
      <app-item-detail [item]="currentItem"></app-item-detail>
    
  1. 在父元件類別中,為 currentItem 指定一個值:

    In the parent component class, designate a value for currentItem:

export class AppComponent { currentItem = 'Television'; }
src/app/app.component.ts
      
      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 OnChangessection 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.

  1. 在子元件類別中匯入 OutputEventEmitter

    Import Output and EventEmitter in the child component class:

    import { Output, EventEmitter } from '@angular/core';
          
          import { Output, EventEmitter } from '@angular/core';
        
  2. 在元件類別中,用 @Output() 裝飾一個屬性。下面的例子中 newItemEvent 這個 @Output() 的型別為 EventEmitter ,這意味著它是一個事件。

    In the component class, decorate a property with @Output(). The following example newItemEvent @Output() has a type of EventEmitter, which means it's an event.

    @Output() newItemEvent = new EventEmitter<string>();
    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 parent

newItemEvent - 這個 @Output() 的名字

* newItemEvent—the name of the @Output()

EventEmitter<string> - 這個 @Output() 的型別

* EventEmitter<string>—the @Output()'s type

new 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.

  1. 在同一個元件類別中建立一個 addNewItem() 方法:

    Create an addNewItem() method in the same component class:

    export class ItemOutputComponent { @Output() newItemEvent = new EventEmitter<string>(); addNewItem(value: string) { this.newItemEvent.emit(value); } }
    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>Add an item: <input #newItem></label> <button (click)="addNewItem(newItem.value)">Add to parent's list</button>
src/app/item-output/item-output.component.html
      
      <label>Add an item: <input #newItem></label>
<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); } }
src/app/app.component.ts
      
      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

  1. 在父範本中,把父元件的方法繫結到子元件的事件上。

    In the parent's template, bind the parent's method to the child's event.

  2. 把子元件選擇器(<app-item-output>)放在父元件的範本 app.component.html 中。

    Put the child selector, here <app-item-output>, within the parent component's template, app.component.html.

    <app-item-output (newItemEvent)="addItem($event)"></app-item-output>
    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>
          
          <ul>
      <li *ngFor="let item of items">{{item}}</li>
    </ul>
        

    *ngFor 會迭代 items 陣列中的條目。當你在子元件的 <input> 中輸入一個值並單擊該按鈕時,子元件就會發出該事件,而父元件的 addItem() 方法會把這個值追加到其 items 陣列中,並且列表中會渲染出這個新條目。

    The *ngFor iterates over the items in the items array. When you enter a value in the child's <input> and click the button, the child emits the event and the parent's addItem() method pushes the value to the items 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>
src/app/app.component.html
      
      <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>,它所帶的 itemdeleteRequest 是子元件類別中的 @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.