iT邦幫忙

DAY 11
0

我在前端 ng 時系列 第 11

ng-filter 的五四三

AngularJS 提供的 filter 無法滿足我們顯示的種種需求。

所以完成一個專案,大部分都會需要自己寫 filter 的。

範例:

  1. 後端傳來的值是

    obj {
    user_installed: true
    }

我們想要畫面呈現的是 "已安裝"。

<div> {{ obj.user_installed | userInstalled }}</div>





app.filter('userInstalled', function () {
     // obj.user_installed 的值
     return function (isInstalled) {
     // 判斷後並回傳對應的 string
     return isInstalled ? '已安裝': '還沒安裝';
   }
  })
  1. 顯示使用者的 ranking
    後端會傳數字,可是前端要用愛心表示 ranking。

    app.filter('myLove', function () {
    return function (num) {
    if (angular.isNumber(num)) {
    var str = '';
    for (var i = 0; i < num; i++) {
    str += '❤';
    }
    return str;
    }
    return '';
    }
    })


客製化 filter 能做的除了單純轉換 String 樣式,還可過濾 array, date, 等不同 type 的參數。
(ex: 昨天陣列 filter 範例)

也可以在 filter 中,用 DI 作法實作複數篩選。(dependency injection $filter module)
ex: 畫面上的價錢自動加上 10,000

app.filter('updateMoney', function ($filter) {
    return function (money) {
      return $filter('currency')(money + 10000);
    }
  })

完整範例:http://plnkr.co/edit/1ABg67uVGzJeQ4kRuaww?p=preview
還有另外作法(註一)


本篇重點來了!Filter 的小心得:

  1. filter 不會修改 argument input value
    filter 的好處除了很方便修改畫面呈現的樣式外,它在過濾資料時不會修改本身 input value。
    打個比方,上面自動加 10,000 的範例,就算我在 filter 上寫 $filter('currency')(money + 10000);

可是真正的 money value 還是會維持原本的 2,000。
不必擔心過了 filter 後,value 會被修改的問題。

  1. filter 會跑兩次

由於 AngularJS dirty-check 的關係,filter 會使 filter function 跑兩次。(註二)
(嚴格來說,是任何的 data-binding 都會跑兩次以上)

所以我建議 filter 中的邏輯不能複雜,會造成效能問題。
(請想像有超過一萬筆資料的陣列跑 loop 兩次的後果..)

3. 使用 Lo-Dash 增加效能

我的習慣是陣列的 filter,我幾乎會改放在 controller 裡,並用 Lo-Dash 做篩選。
因為 Lo-Dash 的過濾陣列動作比較單純,
而 AngularJS 的 filter 因要符合 AngularJS 的總總特性,還會多做些檢查跟跑 methods。
參考 jsperf http://jsperf.com/angularvslodashfilter

<div ng-repeat=“item in myList()"></div>






app.controller(‘myCtrl’, function ($scope, $filter) {
     var ctrl = this;
     ctrl.myList = function () {
         return _.sortBy(list, function (item) {
               return item.price;
          });  
     }
})

4. 畫面上的值是固定的,就不要用 Filter 了!
假如畫面的值在一開始 controller 初始化後,你就知道不會改變了。(static value)
建議直接在 controller 裡完成初始化的動作後就不要再操作了。
就是不用包在 function 裡,也不用 inline-filter 去做任何會發生 data-binding 的操作。
(也可以使用 bindonce + filter 做事情,這是另外一個故事了..)

<!— 不會改變 —>
<div ng-repeat=“item in myList"></div>






app.controller(‘myCtrl’, function ($scope, $filter) {
     var ctrl = this;
     ctrl.myList =  _.sortBy(list, function (item) {
               return item.price;
     }
}) 

**(註一)

這個例子也可以使用在 html 上呼叫多個 filter 的方式
範例:

<div>{{Ctrl.oMoney | updateMoney | currency }}</div>

app.filter('updateMoney', function ($filter) {
    return function (money) {
      return money + 10000;
    }
  }) 

** (註二 參考文章)

http://www.bennadel.com/blog/2489-how-often-do-filters-execute-in-angularjs.htm


上一篇
初談 ng-filter
下一篇
初談 ui-router
系列文
我在前端 ng 時30

尚未有邦友留言

立即登入留言