上一回我們用AngularJS完成最基本的加入項目功能,而就Todo List來說,當然有加入,就要有刪除,才能知道事情做完了。
這回的刪除功能,借助AngularJS的力量,我們一樣不用寫太多code。
我們會在controllers.js新增一個TodoCrtlRemovable的function,它其實是上回TodoCrtl加上移除的功能而已,之所以要另啟一個function來做,只是為了說明與對照上的方便,就實務上,把新加入的功能放進TodoCrtl中就可以了。
這回刪除的功能,主角是Filter。
就AngularJS的模板(template)設計哲學來說,它非常強調像是條件式、迴圈這些東西,應該是屬於Controller的範圍,模板上不應該看見它。但模板上有時有非得有這些東西,這時AngularJS就會提供一些工具來協助。例如上次看到的ng-repeat,以及我們這次要談的Filter。
【模版加入刪除的機制】
照例,先來看我們的html檔,我們把上次的檔案複製一份,重新命名為todoWithRemove.html,然後改寫內容如下。
<html ng-app>
<meta charset="utf-8">
<title>邊學AngularJS邊做Todo List (3)</title>
<script type="text/javascript" src="http://code.angularjs.org/angular-1.0.1.min.js"></script>
<script type="text/javascript" src="js/controllers.js"></script>
<body ng-controller="TodoCrtlRemovable">
<h1>Todo List</h1>
<form ng-submit="addItem()">
<input type="text" ng-model="newItem" name="newItem" />
<input type="submit" id="submit" value="新增待辦事項" />
</form>
<ul id="todo">
<li ng-repeat="item in todoList | filter:{isFinish:false}">
<input type="checkbox" ng-click="removeItem(item)">
{{item.label }}
</li>
</ul>
<hr>
<h1>Finished!</h1>
<ul id="finish">
<li ng-repeat="item in todoList | filter:{isFinish:true}">
{{item.label}}
</li>
</ul>
完成後的樣子應該是如此:
首先我們把ng-cotroller對應到TodoCrtlRemovable,剛剛說過,我們會在這個controller加上刪除的功能。
<body ng-controller="TodoCrtlRemovable">
<ul>的部分,現在變成兩個,一個是上次完成的待辦事項清單,我們加上了id#todo識別。
另一個id#finish,則是我們準備用來放置已經完成工作的事情。
這兩個<ul>基本上結構一樣,只有下列幾個地方不同
(1) #todo與#finish都有一個物件當filter參數,只是參數的值不同。當isFinish標示為false時,表示尚未完成,標示為true則表示已完成。
(2) #todo多了一行:
<input type="checkbox" ng-click="removeItem(item)">
這是我們為辦待事項增加一個核取方塊,當核取方塊點擊時,ng-click這個指令就會監聽到,進而執行刪除的動作(執行removeItem這個事件處理器,參數則是代表自己的item)。
模板的部分,只要加入這些東西就完成刪除工作的所需要的動作。
很容易理解吧。
【Filter究竟是什麼?】
AngularJS提供了一系列的Filter,讓開發者可以用來清理資料,例如:lowercase、uppercase、orderBy、currency、date,這些filter大概都可以望文生義,是用來清理諸如文字大小寫轉換、排序、貨幣、日期等。
舉例來說,{{ ‘HELLO’ | lowercase }} 的結果,就是會變成 ‘hello’。
filter的基本用法就是像上面這樣{{ expression | filter }}
另外filter後面有的可以接參數,例如
{{ 3.1415926 | number:2 }}
輸出結果就會是 3.14。
而我們所使用的filter則是一個通用型的過濾器,你可以指定字串、物件或函式給它當過濾條件。以我們的例子來說,我們提供一個物件,裡面的過濾條件就是isFinish的值。這樣的設計,相當直觀易懂。
因此當todoList這個陣列在取出待辦事項時,#todo只會列出isFinish為false的部分。相對的,#finish則只會取出isFinish為true的事項。
關於filter更詳細的介紹,可以參考:http://docs.angularjs.org/api/ng.filter:filter
【刪除的Controller】
比起Layout,Controller要動的地方更少。
Controller的程式碼如下:
function TodoCrtlRemovable($scope) {
$scope.newItem = '';
$scope.todoList = [];
$scope.addItem = function(){
if(this.newItem){
this.todoList.push({label:this.newItem,isFinish:false});
this.newItem = '';
}
}
$scope.removeItem = function(item){
item.isFinish = true;
}
}
在原本addItem的函式中,我們替待辦事項加上isFinish這個屬性,預設值是false,因為剛新加上的事情,就是還沒做的狀態。
this.todoList.push({label:this.newItem,isFinish:false});
另外,我們要寫removeItem這個函式,來為我們刪去完成的項目,這個函式的寫法,就是把變動的項目當參數傳入,然後改寫它的isFinish的值而已。
$scope.removeItem = function(item){
item.isFinish = true;
}
由於我們把刪除的點擊核取方塊動作和removeItem綁定,因此只要點擊待辦事項的核取方塊,它的isFinish狀態就會被設成true。歸功於AngularJS雙向資料綁定的特性,只要你的model值有異動,view也會跟著改變。換句話說,我們只是把isFinish的值改為true,AngularJS就會幫我們把完成的事項拉到下面的完成列表中。
就這樣,刪除的功能寫完了。
現在你可以去打開todoWithRemove.html來玩一下,完成的樣子應該就是如此。
沒體驗過之前,你是不能感受有多神奇的啊。
邊學AngularJS邊做Todo List (1) - Hello World
邊學AngularJS邊做Todo List (2) - Todo List 動起來
邊學AngularJS邊做Todo List (3) - Todo List 刪項目
邊學AngularJS邊做Todo List (4) - 修改待辦事項
邊學AngularJS邊做Todo List (5) - 為測試作準備
邊學AngularJS邊做Todo List (6) - E2E測試(上)
既然只是修改,那就有更简单的做法:首先,控制器中不需要写removeItem方法;其次,将上面的thml代码的第17行换成<input type="checkbox" ng-checked="item.isFinish" ng-model="item.isFinish" />即可。