[功能介紹-8] Pipes

Pipes有那些?

常用的Pipes有DatePipeUpperCasePipeLowerCasePipeCurrencyPipe,和PercentPipe。它們都可用於任何模板。

下面是angular內建所有的的Pipes說明:

如何使用Pipes

管道將數據作為輸入並將其轉換為所需的輸出。下面是使用DatePipe的範例。

在Pipes裡使用參數

請見下面的範例

這樣會顯示結果如下:
MM/dd/yy:04/15/88
shortDate:04/15/1988
fullDate:Friday, April 15, 1988

串接多個管道

下面為一個例子

結果會顯示
FRIDAY, APRIL 15, 1988

定義自己的Pipes

下面是一個自製Pipes的例子:

在上面的例子中可以看到

  • 會以@Pipe({name:’XXXX’})來宣告這個class是一個pipe
  • pipe類別需implements PipeTransform介面並依照要input的值來選擇要實作的transform方法
  • transform有一個可選參數exponent,可讓使用者帶要帶入的參數進Pipes
  • Pipe的名字需要是一個合法的Javascript命名

下面是一個使用範例

顯示的結果如下:

在每次被綁定的值更動時,都會再跑一次Pipes的功能,一般來說,Pipe只會偵測值的變化才會執行pure Pipes。如對象是String、Number、Boolean、Symbol、Date、Array」Function、Object。但如果裡面是一個物件,則pure Pipes會忽略他的更動。
這是因為效能的考量,若為純粹物件的值的更動在偵測上較快,但是在物件上屬性的更改的偵測效能會較差。會建議改使用元件的方式去偵測改變。

但angular還是提供了impure pipes的方式可以偵測物件的改變,但使用上要小心不能因此而拖慢系統速度。
它看起來會是像這樣:

[功能介紹-7] Structural Directives

什麼是結構指令

結構指令負責HTML佈局。他們通常通過添加,刪除或操縱元素來塑造或重塑DOM的結構。結構指令很容易識別。通常會有星號(*)在指令屬性名稱前面。

以下是三種常件的結構指令的範例

一個attribute directive改變了元素的外觀或行為。例如,內置的NgStyle指令同時改變幾個元素樣式。
而Structural Directives則是會自動將裡面的內容儲存成一個ng-template並且操縱它,這也是為什麼這些指令前面會有一個星號(*)。
其實這個星號會悄悄的讓這個directive成為structure的directive
例如

其實等同於

我們可以觀察到

  • *號將該ngIf改為一個屬性綁定的元素,並綁定一個ng-template。*ngIf <ng-template> [ngIf]
  • 剩下的部分<div>,包括它的class屬性,移到了<ng-template>元素之下。

我們可以將許多屬性指令寫在同一個host element上,但同一個host element只能夠有一個結構指令。

ng-template

從上面*所做的事情,我們可以知道,結構型指令是建立在ng-template之上的。
一個ng-template並不會一開始就顯示在畫面上,而是通過directive去操作裡面的dom並將要顯示的template添加在dom之中。

因此,*ngIf隱藏掉的物件,和我們使用css去show、hide在意義上是完全不同的。
因為它已經不在dom之上,是沒辦法被操作的。

不過由於若是網頁內的資料量大,angular有足夠的理由這樣做。
因為這可以避免過多的dom元素拖累網頁效能,若單純使用css去hide、show元素,所有的監聽器、物件依舊會在背景執行,這會讓效能變得不佳。
如果我們需要在show、hide物件的同時執行一些特殊的指令,可以用Lifecycle Hooks來撰寫此時要做的事情。

如何套用多個結構指令在元件裡

上面有提到,我們可以將許多屬性指令寫在同一個host element上,但同一個host element只能夠有一個結構指令。
所以在一般的狀態下,如果需要兩個標籤,我們會將HTML利用一些不會影響結構的標籤來做多層的Structural Directives控制

但有時候該狀況不允許任何多餘的標籤在裡面,例如下拉選單select。
若有一個區域選單select裡面的option內容要由*ngFor來產生,但是當city未選擇時,select又希望不要有任何下拉選單,
這時後我們在option上的確同時會需要放許多個結構指令,但ANGULAR不允許同一個標籤上放兩個結構指令。

如果我們多包一層span去包裡面的內容,會發現因為select內不允許span標籤,會造成讀不到option下拉選單,即便已經選擇了city


這時候就可以改用<ng-container>

就可以正常顯示了

自製一個結構Directive

最重要的地方是在@Input那段,展示了如何去操作dom
使用的地方如下:

完整範例請見:live example / download example

[功能介紹-6] Attribute Directives

Directive有分為結構型和屬性型的,這一篇要先介紹屬性型的Directive。
本篇的範例請見:Attribute Directive example / download example

Angular有三種directive:

  • 元件 – 包含template的directive。
  • 結構指令 – 通過添加和刪除DOM元素來更改DOM佈局。(如ngFor、ngIf)
  • 屬性指令 – 改變元素,組件或其他指令的外觀或行為。(如ngStyle)

建立一個簡單的屬性型directive

一個directive最少需要一個帶有@Directive宣告的檔案,告訴angular該如何識別這個directive。
這邊會用一個high light的directive範例來解說,當用戶將鼠標懸停在該元素上時,設置元素的背景色。你可以像這樣應用它:

而下面會一步步創立這一個directive。

首先,用cli創立一個新的directive

會看到cli自動建立了兩個新的檔案

產生的src/app/highlight.directive.ts檔案的內容如下:

當我們import了Directive後,就可以在檔案內使用@Directive來設定directive的CSS attribute selector
方括弧[]可以讓它成為一個屬性選擇器,在這邊為什麼會取為appHighlight而不是highlight,是為了避免與現有的html指令衝突,建議最好在所有的directive前面加上前綴字,以方便識別這是那邊來的屬性。如果沒有前綴字,很容易會發生難以識別的錯誤

接著看src/app/highlight.directive.ts的內容:

這邊可以看到在建構子的地方會傳入ElementRef,並且使用el.nativeElement直接修改DOM元素的背景顏色。

若希望directive能夠接收使用者事件,可以加載HostListener,如下:

顯示的結果如下圖:

當然,也可以通過標準的JavaScript來訪問DOM,並手動添加事件監聽器。這種方法至少有三個問題,是不被建議的:

  • 需正確的堅聽到各種平台的事件
  • 當要destroy這個directive時要手動移除事件
  • 直接操作DOM API不是好的方式

輸入參數至directive

首先要先import所需的Input

然後宣告所要輸入的變數

那麼在使用directivet傳入參數的方式有下面幾種

下面這個範例是使用上面自製的directive,讓使用者選擇highlight的顏色
template檔案內容如下:

component內容如下:

最後結果如下圖: