上方廣告

2017年6月1日 星期四

[Angular學習紀錄] @Input() or @Output()

Angular可以透過在HTML標籤內使用DOM的Property綁定的方式將資料由Component端傳送到Template端(又或者反向綁定、雙向綁定)。

但該方式指的都是同一個Template,若假設有一種情境為,一個父親的Template必須要將值傳送到兒子Template,並且兒子Template內處理完某些事件必須要將資料傳送回父親Template的情境時,該如何進行?

PS. 有點類似早期的showModalDialog在兩個父子視窗傳值的概念,只是在此Single Page Application(SPA)的情境中不是兩個不同的頁面,因此使用方式也有所不同。


首先必須要先理解Angular在屬性綁定的對應關係,舉個例子[value] = "hero.name"。
上面這個表達式的關係可參考底下Angular的官方說明,說的很清楚,若你不想要逐一看官網的敘述的話,容我用白話文簡短的來翻譯一下,上面的表達式以等號當作切點來看,大致如下三點說明。

  • 等號的左邊為綁定的目標。 
  • 等號的右邊為綁定的來源
  • 某些條件下目標會受到限制只能綁定到標記為InputOutput的屬性,例如,綁定到兒子Template的目標(這個就是本文要說明的部分)。

Note the important distinction between a data binding target and a data binding source
The target of a binding is to the left of the =. The source is on the right of the =.
The target of a binding is the property or event inside the binding punctuation: []() or [()]. The source is either inside quotes (" ") or within an interpolation ({{}}).
Every member of a source directive is automatically available for binding. You don't have to do anything special to access a directive member in a template expression or statement.
You have limited access to members of a target directive. You can only bind to properties that are explicitly identified as inputs and outputs.


理解了綁定關係後,再開始範例說明之前,先簡單的說明一下兩個裝飾器 (Decorators),@Input() & @Output(),這兩個Decorators的使用方式在後面的範例中將會提到。
  • @Input() : 輸入屬性,通常為接收數據資料,也就是就是讓Parent將資料傳送到Child中使用。
  • @Output() : 輸出屬性,通常提供事件給外部呼叫回傳使用,也就是讓Child將資料傳回Parent中使用。

下圖是Angular官網中擷取出來的說明圖,主要是想要表達Input和Output這兩個詞是從目標(也就是Child)指令的角度來看的。



接下來就示範一下 @Input() 和 @Output 的寫法,下圖是本範例最終跑出來的結果,請特別留意一下我將 @Input() 和 @Output() 兩個 Decorators 都放在 Child 模板內,這個是有意義的,稍後程式碼的部分可以觀察一下。

  • 紅色標示(輸入),就是將父親的輸入傳遞到兒子模板。
  • 綠色標示(輸出),就是由兒子模板引發事件將資料回傳到父親模板。


好了,範例正式開始,先來看一下 Parent Template和 Child Template 的語法,在模板語法的部分,觀察一下父親模板內宣告兒子模板的語法,回想一下剛剛說明 Input 和 Output兩個裝飾器分別代表的意思,可以看出底下兩個部分。

  • [parentValue] 代表兒子模板所提供的接收輸入,也就是@Input(),"strToChild" 代表父親傳入的資料來源
  • (childEvent) 代表兒子模板所提供的輸出事件,也就是@Output(),"onListenChild($event);" 代表父親模板內會被回傳觸發的事件


Parent Template如下參考
<fieldset>
  <legend>
    <h1>我是父親</h1>
  </legend>
  <input [(ngModel)]="strToChild"><br>
   我是兒子的時間 => <span style='color:red'> {{ strFormChild | date : 'yyyy-MM-dd hh:mm:ss'  }} </span>
</fieldset>

<!-- 底下為Child模板的宣告-->
<detail [parentValue]="strToChild" (childEvent)="onListenChild($event);"></detail>

Child Template如下參考
<fieldset>
  <legend>
    <h3>我是兒子</h3>
  </legend>
  <div>
      來自於父親傳送的資料 => <span style='color:red'> {{ parentValue }} </span>
      <br>
      <button (click)="onChildClick()">回傳父親時間</button>
  </div>
</fieldset>


Parent Component的部分,這裡觀察一下兩個部分。

  • strToChild,要將資料傳遞給 Child 屬性。
  • onListenChild($event : any),Child 端事件發生後回Call此方法,此處的參數是由 Child 端注入。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  strToChild = '我是父模板的資料'; //父親模板的初始值
  strFormChild = ''; //<==兒子的回傳值的顯示屬性

  //Child模板事件發生時,會呼叫此方法回傳值
  onListenChild($event: any) {
    this.strFormChild = $event as string;
  }
}


最後也是最重要的部分了,Child Component的部分,一樣觀察兩個部分。

  • @Input(),為parentValue屬性增加 Input Decorator,如此才能讓 Parent Template 當成目標屬性,並將來源資料提供給 Child。
  • @Output(),為childEvent事件增加 Output Decorator,並將該事件提供給事件發射器(EventEmitter)管理,如此才能讓 Parent Template 當成目標事件,請注意<Date>,此處Date為準備回傳給 Parent 的參數類型,可依需求自行定義。
  • 另外 Parent 內自行定義了一個按鈕的事件(取得當前日期時間),當按鈕 Click 事件發生時,就會呼叫 EventEmmitter 的 emit 方法,將想要回傳給 Parent 的資料傳送回去


import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'detail',
  templateUrl: './detail.component.html'
})
export class DetailComponent {
  @Input() parentValue: string; //提供Input裝飾器,讓該屬性成為父親模板的屬性
  @Output() childEvent = new EventEmitter<Date>(); //提供Output裝飾器,讓該事件成為父親模板的事件

  onChildClick() {
    this.childEvent.emit(new Date());
  }
}


重點回顧


  • @Input() : 輸入屬性,通常為接收數據資料,也就是就是讓Parent將資料傳送到Child中使用。
  • @Output() : 輸出屬性,通常提供事件給外部呼叫回傳使用,也就是讓Child將資料傳回Parent中使用。


本文撰寫時Angular版本為v4.0。

本文範例下載 : Github,使用Angular CLI。

參考網站
[Day 19] Angular 2 Input(s) & Output(s) 傻傻分不清
Angular 官網 Input and output properties ( @Input and @Output )