這篇實在寫太久了.....學得十分緩慢,雜事實在太多....
但有學到總是好的,所以照慣例記錄一下學習心得
以下開始前言 :
ng-repeat 這個 directive 前幾篇有偷用過很多次了~
這篇要來學習的是 ng-repeat 的一般與進階用法,還有使用時的注意事項
然後這篇決定將程式碼上色一下,不然有點難閱讀....= =
然後下面的程式碼都可以切換到 result 頁簽看執行結果
一樣有目錄
2. DOM的產生,與 ng-repeat-start、ng-repeat-end 的使用
3. 使用ng-repeat 會遇到的問題,與 track by (追蹤)
4. 使用 orderBy 對 ng-repeat 進行排序
5. 使用 limitTo 限制 ng-repeat 的筆數
ng-repeat 使用方式
官網文件在這邊 :
https://docs.angularjs.org/api/ng/directive/ngRepeat
ng-repeat 主要功能就是將樣板中的內容依照來源的資料,重複產生DOM元素
ˊ而資料的來源分成兩種,陣列或物件
1. 陣列
HTML :
執行後就會出現 :
1
2
3
或是像下方這樣陣列在 controller 裡面
2. 物件
因為物件會有 key 跟 value 值,所以是用以下的方法抓取資料
HTML :
JS :
結果就會像下面這樣 :
ng-repeat 也有提供幾個特殊的變數,如下面官網的資料
Variable | Type | Details |
---|---|---|
$index |
number | iterator offset of the repeated element (0..length-1) |
$first |
boolean | true if the repeated element is first in the iterator. |
$middle |
boolean | true if the repeated element is between the first and last in the iterator. |
$last |
boolean | true if the repeated element is last in the iterator. |
$even |
boolean | true if the iterator position $index is even (otherwise false). |
$odd |
boolean | true if the iterator position $index is odd (otherwise false). |
底下就來 try try 看
1. $index
$index 就是目前索引跑到了第幾個項目,索引是從0開始,直接看範例最清楚了
用剛剛的範例再加上 {{ $index + 1 }} 來跑出序號
2. $first
$first 指的是迴圈中的第一列,如果是第一列就是 true
所以可以用這個 $first 來判斷是不是第一筆資料,下面例子順便用上了上一篇的 ng-class
3. $middle
$middle 指的是迴圈中間的內容,所謂中間的內容就是排除 $first 第一筆,與排除 $last 最後一筆
範例一樣透過 ng-class 來表示囉
如果剛好是迴圈中間的資料 $middle 就會是 true,然後就會套用 middle 這個 class
4. $last
$last 指的就是所有資料的最後一列
5. $even
$even 指的是偶數列,但要注意索引是從 0 開始喔
6. $odd
$odd 指的是奇數列
DOM的產生,與 ng-repeat-start、ng-repeat-end 的使用
接下來要來看一下 ng-repeat 實際是怎麼產生 DOM 的,如以下的範例
執行後變這樣,再檢視原始檔可以發現,ng-repeat 是重複指示詞所在的那個 html 標籤本身
除了重複產生 DOM,連原本的 ng-repeat 屬性都會一併複製,還順便多了 class="ng-binding ng-scope"
其實我剛開始使用的時候一度以為他是重複跑指示詞所在html標籤內的子元素
可能 .net 寫習慣了.....net 的 repeat 是跑樣板內的內容,就像下面這樣
<asp:Repeater ID="repeater" runat="server">
<ItemTemplate>
<div><%#Eval("DisplayName") %></div> // 人家會重複的只有這行
</ItemTemplate>
</asp:Repeater>
既然搞清楚 ng-repeat 是重複所在的標籤本身 + 其內部的子元素,現在又衍伸一個另外的問題
因為有時候要重複的區塊可能是多個,而且不包含在 ng-repeat 所在的標籤容器內
例如以下的例子 :
執行後就會變這樣
================
姓名: | bill |
姓名: | jack |
姓名: | john |
姓名: | mary |
年齡: |
但其實我是想要這樣
================
姓名: | bill |
年齡: | 22 |
姓名: | jack |
年齡: | 19 |
姓名: | john |
年齡: | 18 |
姓名: | mary |
年齡: | 20 |
但是因為只能重複一個 tr 本身跟他的子元素, 所以要做到想要的結果有點困難
所以 ng-repeat 有提供了另一種方法來解決這個問題,就是使用 ng-repeat-start、ng-repeat-end
從 ng-repeat-start 開始到 ng-repeat-end 結束的範圍內都會被複製,並且都可以取得 repeat 的來源物件
所以上面的範例改成這樣就解決了
完整範例如下
使用ng-repeat 會遇到的問題,與 track by (追蹤)
上面有提到,ng-repeat 會反覆瀏覽物件或陣列中的每個值,用來產生新的 DOM 元素
但是為了效能最佳化會根據物件的 hash (AngularJS 所決定的) 來判斷是否要使用原有DOM元素或是重新產生 DOM 元素
上面這段話可能有點難懂
但其實你用來跑 ng-repeat 的來源"物件"都會被加上一個 $$hashKey 的值,用來跟產生的 DOM 作對應
有了$$hashKey 跟DOM 對應,AngularJS 才會知道異動的是那些資料,然後來決定是否要重新產生 DOM元素
看一下以下的例子 :
在按下"刪除最後一筆"的時候雖然被刪除了,但其他 $$hasKey 的值都沒改變
按下重新取得後,因為已經是不同執行個體了,所以AngularJS 就判斷需要重新產生
然後物件會有 $$hashKey,但陣列預設是用陣列的內容來當 key 值的喔 (陣列也沒法附加延伸屬性)
所以如果你的陣列中有內容重複的話,如下有兩個 1 重複了
就會發生如下的錯誤訊息 :
因為對 ng-repeat 來說,能夠辨別的索引鍵重複了
針對這種狀況 AngularJS 提供了 track by 來設定 ng-repeat 的鍵值 (追蹤ID)
下面的 code 就設定了上面提到的 $index 變數來當 track id
結果就會正確的如下所顯示了
如果你的物件來源是資料庫,也可以指定成資料表中的索引值,ex : track by obj.id 來確保不會重複
除了以上方法也可以使用 track by $id( $index),$id() 則是會將傳入的物件回傳出一個對應的雜湊資料
使用 track by 除了解決造成錯誤訊息的問題,也可以減少頻繁的重複更新DOM元素,進而提高效能
可以參考一下高手們寫的這幾篇 :
或是參考以下自己仿照測試的範例
加上 track by 之後就可以讓DOM重複被利用了
使用 orderBy 對 ng-repeat 進行排序
ng-repeat 可以加上 orderBy 來幫來源資料進行排序,如以下的範例 :
結果就會如下 : (自己切換到 result 頁簽看結果)
使用 limitTo 限制 ng-repeat 的筆數
ng-repeat 可以加上 limitTo 來限制資料的筆數,像下面的範例 :
加上負號就是從後面開始取資料
使用 filter 過濾器來過濾來源資料
ng-repeat 也可以使用 filter 來過濾資料
例如以下這樣 :
其他更詳細的 filter 用法之後再學邊寫囉~~~
AngularJS 學習筆記系列 : (依本人的上進心持續增加)
AngularJS 初學者筆記與教學 (一) - 使用方式、Expression、Controller、Module
AngularJS 初學者筆記與教學 (二) 內建的簡單指令之1 ng-click、ng-show、ng-hide
AngularJS 初學者筆記與教學 (三) - AngularJS 的載入流程與 ng-cloak 運作原理
AngularJS 初學者筆記與教學 (四) - 如何動態改變 CSS 樣式,使用 ng-class、ng-style
AngularJS 初學者筆記與教學 (五) - 繼續深入學習常用的 ng-repeat
AngularJS 初學者筆記與教學 (新手入門課程 - 課後心得篇)
AngularJS 初學者筆記與教學 (七) - FormController 的表單驗證與資料檢查
留言列表