本節中,我們將使用 過濾器(filter) 把手機詳情中的true 與 false ,換成瀏覽體驗更高的 <i style="color:green" class="icon icon-check"></i> 與 <i style="color:red" class="icon icon-cross"></i>

# 找到兩個圖標

對每天學習半小時v3.bootcss.com的我們,相應找到這兩個圖標的時間不會超過30S,如果你的時間超出了30S,那么說明你學習v3.bootcss.com的時間還不夠。
> 簡單的事情重復做,你就是專家;
重復的事情認真做,你就是贏家。
**重復,多么簡單的事情,今天你做到了嗎?**
# 認識過濾器
在前面的循環過濾器中,我們已經接觸過了 過濾器。過濾器不僅實現 按過濾條件進行顯示 的功能,還可以實現怎么顯示、顯示什么的功能。
在實際的項目中,比如對日期的格式化、對用戶狀態正常、凍結的格式化,對直接輸出到頁面的HTML的格式化,對金錢的格式化等等,我們將大量的與過濾器打交道。
下面,我們定義第一個過濾器,來實現false與true的人性化顯示。
## 建立模塊
由于過濾器往往會在多個項目中使用,或是說一旦有了過濾器,我們會使用在我們所涉及到的所有項目中。所以我們在此新建一個名為core的模塊。
`core/core.module.js`
~~~
// 定義一個core模塊,供模塊內的組件使用。
angular.module('core', []);
~~~
## 建立過濾器
建立模塊時,我們命名為xxx.module.js;建立組件時,我們命名為xxx.component.js;建立模板文件時,我們命名為xxx.template.js;同樣,建立過濾器時,我們命名為xxx.filter.js
`core/checkmark/checkmark.filter.js`
有了說,老師為什么不是`core/checkmark.filter.js`而是`core/checkmark/checkmark.filter.js`,這當然是為了以后的擴展做準備了。
我們回想下建立component時的代碼,再回想下配置路由的代碼,照貓畫虎(軟件工程中叫做 抽象),我想大概我們也能猜出這個filter需要怎樣定義了。
1 基本結構
~~~
angular.
module('core').
filter();
~~~
2 添加參數
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){});
~~~
3 擴充功能代碼
在過濾器的功能代碼中,會直接返回一個 function , 然后模板在調用filter時,將原值值入filter, filter經過內部的函數處理后,將處理的結果返回給模板.
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){
// input為模板傳入的變量
return function(input){};
});
~~~
4 具體代碼實現
我們簡單的返回一個hello yunzhi試試
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){
// input為模板傳入的變量
return function(input){
return 'hello yunzhi';
};
});
~~~
這里面有兩個return, 第一個return返回了一個function,此function供模板進行調用,并將模板中的變量做為參數(input)傳入。第二個retrun,是將input進行處理后的返回值,該值將直接顯示在模板中。
5 測試
我們在模板中加入過濾器,進行測試
5.1 引用JS文件
`index.html`
~~~
+ <script src="core/core.module.js"></script>
+ <script src="core/checkmark/checkmark.filter.js"></script>
~~~
5.2 注入core模塊
`app.moudle.js`
~~~
// 定義模塊
var phonecatApp = angular.module('phonecatApp', ['yunZhi', 'ngRoute', 'core']);
~~~
5.3 更改模板,加入過濾器
`yun-zhi/phone-detail.template.html`
~~~
<dt>Infrared</dt>
- <dd>{{$ctrl.phone.connectivity.infrared}}</dd>
+ <dd>{{$ctrl.phone.connectivity.infrared | checkmark}}</dd>
<dt>GPS</dt>
- <dd>{{$ctrl.phone.connectivity.gps}}</dd>
+ <dd>{{$ctrl.phone.connectivity.gps | checkmark}}</dd>
~~~

沒錯,我們看到以前的false和true就變成hello yunzhi了。
其實在這個過濾器中,我們并沒有使用到模板的傳入值。所以即使刪除到input參數,也不會有任何的問題。當然了,既然是參數,那么名字也是可以更改的,所以我們更改為以下幾種方式,都可以成功執行:
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){
// input為模板傳入的變量
return function(){
return 'hello yunzhi';
};
});
~~~
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){
// input為模板傳入的變量
return function(hello){
return 'hello yunzhi';
};
});
~~~
## 完善過濾器
我的目標,當true時輸出<i style="color:green" class="icon icon-check"></i>,當false時,輸出<i style="color:red" class="icon icon-cross"></i>。
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function(){
// input為模板傳入的變量
return function(input){
// 為true輸出對號,否則,輸出錯號
if (input)
{
return '<i class="glyphicon glyphicon-ok"></i>';
} else {
return '<i class="glyphicon glyphicon-remove"></i>';
}
};
});
~~~
測試:

?說好的<i style="color:green" class="icon icon-check"></i>去哪了?
我們說當顯示的效果與我們的預期不同時,我們首先想到的應該是查看生成的源代碼:

原來,我們返回html標記,被做為普通的字符串處理了。這是由于angularjs出于安全的角度考慮,當它接收到html標記語言時,會自動轉化為普通的字符串,這樣做的好處很明顯:不會破壞模板的結構。
而當我們需要angularjs將返回文本做為html標記時,則需要調用一個叫做`Strict Contextual Escaping(嚴格的上下文模式)`內置服務模塊,簡寫為sce,在angularjs中的名稱為$sce。$sce中有一個方法叫做`$sce.trustAsHtml`, 譯為:做為被信任的html文本。除此以外,還有trustAsUrl, trustAsResourceUrl, trustAsJs 和 trustAsCss
> angularjs內部定義的對象,都以$開頭。$sce的詳細說明, 我們可以在https://angular.org中,直接搜索來找到。當然了,其它的內置模塊也一樣。
## 加入$sce.trustAsHtml
~~~
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', function($sce){
// input為模板傳入的變量
return function(input){
var result;
// 為true輸出對號,否則,輸出錯號
if (input)
{
result = '<i class="glyphicon glyphicon-ok"></i>';
} else {
result = '<i class="glyphicon glyphicon-remove"></i>';
}
return $sce.trustAsHtml(result);
};
});
~~~
如果只在過濾器中,加入$sce.trustAsHtml,這還不夠。我們還需要在模板中使用ng-bind-html來綁定這個可信的html標記:
`yun-zhi/phone-detail.template.html`
~~~
- <dd>{{$ctrl.phone.connectivity.infrared | checkmark}}</dd>
+ <dd ng-bind-html="$ctrl.phone.connectivity.infrared | checkmark"></dd>
...
~~~
測試:

換成ng-bind-html后,我們想要的效果已經呈現在了我們面前。
## 代碼重構
在開發中,將我們功能開發完畢后,下一步就是對代碼重構。代碼的重構能夠增加易讀性,大幅的減輕日后維護的壓力。
`core/checkmark/checkmark.filter.js`
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', ['$sce', function($sce){
// input為模板傳入的變量
return function(input){
var result = '<i class="glyphicon glyphicon-';
// 為true輸出對號,否則,輸出錯號
if (input)
{
result += 'ok';
} else {
result += 'remove';
}
result += '"></i>'
// 引入$sce返回可信任的html標記
return $sce.trustAsHtml(result);
};
}]);
~~~
正如你看到了,為了避免代碼壓縮引起的問題,我將filter進行了改寫。
* * * * *
`index.html`
~~~
<!DOCTYPE html>
<html lang="en" ng-app="phonecatApp">
<head>
<head>
<meta charset="UTF-8">
<title>hello</title>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-route/angular-route.js"></script>
<script src="app.moudle.js"></script>
<script src="app.config.js"></script>
<script src="yun-zhi/yun-zhi.module.js"></script>
<script src="yun-zhi/phone-list.component.js"></script>
<script src="yun-zhi/hello-yunzhi.component.js"></script>
<script src="yun-zhi/phone-detail.component.js"></script>
<script src="core/core.module.js"></script>
<script src="core/checkmark/checkmark.filter.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
~~~
`app.moudle.js`
~~~
// 定義模塊
var phonecatApp = angular.module('phonecatApp', ['yunZhi', 'ngRoute', 'core']);
~~~
`core/core.module.js`
~~~
// 定義一個core模塊,供模塊內的組件使用。
angular.module('core', []);
~~~
`core/checkmark/checkmark.filter.js`
~~~
angular.
module('core').
// 第一個參數是過濾器名,第二個參數是功能函數
filter('checkmark', ['$sce', function($sce){
// input為模板傳入的變量
return function(input){
var result = '<i class="glyphicon glyphicon-';
// 為true輸出對號,否則,輸出錯號
if (input)
{
result += 'ok';
} else {
result += 'remove';
}
result += '"></i>'
// 引入$sce返回可信任的html標記
return $sce.trustAsHtml(result);
};
}]);
~~~
`yun-zhi/phone-detail.template.html`
~~~
<img ng-src="{{$ctrl.phone.images[0]}}" class="phone" />
<h1>{{$ctrl.phone.name}}</h1>
<p>{{$ctrl.phone.description}}</p>
<ul class="phone-thumbs">
<li ng-repeat="img in $ctrl.phone.images">
<img ng-src="{{img}}" />
</li>
</ul>
<ul class="specs">
<li>
<span>Availability and Networks</span>
<dl>
<dt>Availability</dt>
<dd ng-repeat="availability in $ctrl.phone.availability">{{availability}}</dd>
</dl>
</li>
<li>
<span>Battery</span>
<dl>
<dt>Type</dt>
<dd>{{$ctrl.phone.battery.type}}</dd>
<dt>Talk Time</dt>
<dd>{{$ctrl.phone.battery.talkTime}}</dd>
<dt>Standby time (max)</dt>
<dd>{{$ctrl.phone.battery.standbyTime}}</dd>
</dl>
</li>
<li>
<span>Storage and Memory</span>
<dl>
<dt>RAM</dt>
<dd>{{$ctrl.phone.storage.ram}}</dd>
<dt>Internal Storage</dt>
<dd>{{$ctrl.phone.storage.flash}}</dd>
</dl>
</li>
<li>
<span>Connectivity</span>
<dl>
<dt>Network Support</dt>
<dd>{{$ctrl.phone.connectivity.cell}}</dd>
<dt>WiFi</dt>
<dd>{{$ctrl.phone.connectivity.wifi}}</dd>
<dt>Bluetooth</dt>
<dd>{{$ctrl.phone.connectivity.bluetooth}}</dd>
<dt>Infrared</dt>
<dd ng-bind-html="$ctrl.phone.connectivity.infrared | checkmark"></dd>
<dt>GPS</dt>
<dd ng-bind-html="$ctrl.phone.connectivity.gps | checkmark"></dd>
</dl>
</li>
<li>
<span>Android</span>
<dl>
<dt>OS Version</dt>
<dd>{{$ctrl.phone.android.os}}</dd>
<dt>UI</dt>
<dd>{{$ctrl.phone.android.ui}}</dd>
</dl>
</li>
<li>
<span>Size and Weight</span>
<dl>
<dt>Dimensions</dt>
<dd ng-repeat="dim in $ctrl.phone.sizeAndWeight.dimensions">{{dim}}</dd>
<dt>Weight</dt>
<dd>{{$ctrl.phone.sizeAndWeight.weight}}</dd>
</dl>
</li>
<li>
<span>Display</span>
<dl>
<dt>Screen size</dt>
<dd>{{$ctrl.phone.display.screenSize}}</dd>
<dt>Screen resolution</dt>
<dd>{{$ctrl.phone.display.screenResolution}}</dd>
<dt>Touch screen</dt>
<dd ng-bind-html="$ctrl.phone.display.touchScreen | checkmark"></dd>
</dl>
</li>
<li>
<span>Hardware</span>
<dl>
<dt>CPU</dt>
<dd>{{$ctrl.phone.hardware.cpu}}</dd>
<dt>USB</dt>
<dd>{{$ctrl.phone.hardware.usb}}</dd>
<dt>Audio / headphone jack</dt>
<dd>{{$ctrl.phone.hardware.audioJack}}</dd>
<dt>FM Radio</dt>
<dd ng-bind-html="$ctrl.phone.hardware.fmRadio | checkmark"></dd>
<dt>Accelerometer</dt>
<dd ng-bind-html="$ctrl.phone.hardware.accelerometer | checkmark"></dd>
</dl>
</li>
<li>
<span>Camera</span>
<dl>
<dt>Primary</dt>
<dd>{{$ctrl.phone.camera.primary}}</dd>
<dt>Features</dt>
<dd>{{$ctrl.phone.camera.features.join(', ')}}</dd>
</dl>
</li>
<li>
<span>Additional Features</span>
<dd>{{$ctrl.phone.additionalFeatures}}</dd>
</li>
</ul>
~~~
- 前言
- 第一章:準備知識
- 第一節:GIT
- 第二節:Node.js
- 第三節:http-server
- 第四節:bower
- 第五節:firefox+chrome
- 第二章:官方示例教程
- 第零節:Hello Yunzhier
- 第一節:靜態模板
- 第二節:MVC
- 回調函數
- 第三節:組件
- 第四節:重構組件
- 2.4.1 調用組件
- 2.4.2 規劃目錄結構
- 2.4.3 剝離V層
- 2.4.4 大話測試
- 第五節:循環過濾器
- 第六節:雙向數據綁定
- 第七節:XHR與依賴注入
- 第八節:添加縮略圖
- 第九節:模擬頁面跳轉
- 2.9.1 使用bower
- 2.9.2 使用grunt
- 第十節:完善手機詳情頁
- 第十一節:自定義過濾器
- 第十二節:行為處理
- 第十三節:封裝請求
- 第十四節:應用動畫
- 第十五節:總結
- 第三章:菜譜管理示例
- 第四章:總結