在這一步你會增加一個讓使用者控制手機列表顯示順序的特性。動態排序可以這樣實現,添加一個新的模型屬性,把它和迭代器整合起來,然後讓資料繫結完成剩下的事情。
請重設工作目錄:
git checkout -f step-4
你應該發現除了搜尋方塊之外,你的應用多了一個下來菜單,它可以允許控制電話排列的順序。
步驟3和步驟4之間最重要的不同在下面列出。你可以在GitHub裡看到完整的差別。
模板
app/index.html
Search: <input ng-model="query">Sort by:<select ng-model="orderProp"> <option value="name">Alphabetical</option> <option value="age">Newest</option></select><ul class="phones"> <li ng-repeat="phone in phones | filter:query | orderBy:orderProp"> {{phone.name}} <p>{{phone.snippet}}</p> </li></ul>
我們在index.html中做了如下更改:
首先,我們增加了一個叫做orderProp的<select>標籤,這樣我們的使用者就可以選擇我們提供的兩種排序方法。
然後,在filter過濾器後面添加一個orderBy過濾器用其來處理進入迭代器的資料。orderBy過濾器以一個數組作為輸入,複製一份副本,然後把副本重排序再輸出到迭代器。
AngularJS在select元素和orderProp模型之間建立了一個雙向繫結。而後,orderProp會被用作orderBy過濾器的輸入。
正如我們在步驟3中討論資料繫結和迭代器的時候所說的一樣,無論什麼時候資料模型發生了改變(比如使用者在下拉式功能表中選了不同的順序),AngularJS的資料繫結會讓視圖自動更新。沒有任何笨拙的DOM操作!
控制器
app/js/controllers.js:
function PhoneListCtrl($scope) { $scope.phones = [ {"name": "Nexus S", "snippet": "Fast just got faster with Nexus S.", "age": 0}, {"name": "Motorola XOOM™ with Wi-Fi", "snippet": "The Next, Next Generation tablet.", "age": 1}, {"name": "MOTOROLA XOOM™", "snippet": "The Next, Next Generation tablet.", "age": 2} ]; $scope.orderProp = 'age';}
我們修改了phones模型—— 手機的數組 ——為每一個手機記錄其增加了一個age屬性。我們會根據age屬性來對手機進行排序。
我們在控制器代碼裡加了一行讓orderProp的預設值為age。如果我們不設定預設值,這個模型會在我們的使用者在下拉式功能表選擇一個順序之前一直處於未初始化狀態。
現在我們該好好談談雙向資料繫結了。注意到當應用在瀏覽器中載入時,“Newest”在下拉式功能表中被選中。這是因為我們在控制器中把orderProp設定成了‘age'。所以綁定在從我們模型到使用者介面的方向上起作用——即資料從模型到視圖的綁定。現在當你在下拉式功能表中選擇“Alphabetically”,資料模型會被同時更新,並且手機列表數組會被重新排序。這個時候資料繫結從另一個方向產生了作用——即資料從視圖到模型的綁定。
測試
我們所做的更改可以通過一個單元測試或者一個端到端測試來驗證正確性。我們首先來看看單元測試:
test/unit/controllersSpec.js:
describe('PhoneCat controllers', function() { describe('PhoneListCtrl', function(){ var scope, ctrl; beforeEach(function() { scope = {}, ctrl = new PhoneListCtrl(scope); }); it('should create "phones" model with 3 phones', function() { expect(scope.phones.length).toBe(3); }); it('should set the default value of orderProp model', function() { expect(scope.orderProp).toBe('age'); }); });});
單元測試現在驗證了預設值被正確設定。
我們使用Jasmine的介面把PhoneListCtrl控制器提取到一個beforeEach塊中,這個塊會被所有的父塊describe中的所有測試所共用。
運行這些單元測試,跟以前一樣,執行./scripts/test.sh指令碼,你應該會看到如下輸出(注意:要在瀏覽器開啟http://localhost:9876並進入strict 模式,測試才會運行!):
Chrome: Runner reset...Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms) Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
現在我們把注意力轉移到端到端測試上來。
test/e2e/scenarios.js:
... it('should be possible to control phone order via the drop down select box', function() { //let's narrow the dataset to make the test assertions shorter input('query').enter('tablet'); expect(repeater('.phones li', 'Phone List').column('phone.name')). toEqual(["Motorola XOOM\u2122 with Wi-Fi", "MOTOROLA XOOM\u2122"]); select('orderProp').option('Alphabetical'); expect(repeater('.phones li', 'Phone List').column('phone.name')). toEqual(["MOTOROLA XOOM\u2122", "Motorola XOOM\u2122 with Wi-Fi"]); });...
端到端測實驗證了選項框的排序機制是正確的。
你現在可以重新整理你的瀏覽器,然後重新跑一遍端到端測試,或者你可以在AngularJS的伺服器上運行一下。
練習
在PhoneListCtrl控制器中,把設定orderProp那條語句刪掉,你會看到AngularJS會在下拉式功能表中臨時添加一個空白的選項,並且排序次序是預設排序(即未排序)。
在index.html模板裡面添加一個`{{orderProp}}綁定來即時顯示它的值。
總結
現在你已經為你的應用提供了搜尋功能,並且完整的進行了測試。步驟5我們將學習AngularJS的服務以及AngularJS如何使用依賴注入。
以上就是對AngularJS 雙向繫結的資料整理,後續繼續補充相關資料,謝謝大家對本站的支援!