AngularJS 篩選迭代器

2022-04-15 14:32 更新

篩選迭代器

我們?cè)谏弦徊街袨殚_發(fā)應(yīng)用打基礎(chǔ)做了很多工作,現(xiàn)在我們將做一些簡單的事情;我們將添加全文搜索(是的,它很簡單!)。我們還將編寫一個(gè)端到端測(cè)試,因?yàn)橐粋€(gè)好的端到端測(cè)試可以幫上大忙。它監(jiān)視著你的應(yīng)用,并在發(fā)生回歸時(shí)迅速報(bào)告。

  • 現(xiàn)在應(yīng)用有了一個(gè)搜索框。注意頁面上的手機(jī)列表的變化取決于用戶在搜索框中打了什么字。

把工作空間重置到第三步

git checkout -f step-3

刷新你的瀏覽器或在線檢查這一步:Step 3 Live Demo

下面列出了第二步和第三步之間最重要的區(qū)別。你可以在GitHub里看到完整的差異。

控制器

我們對(duì)控制器不作修改。

模板

app/index.html:

  <div class="container-fluid">
    <div class="row">
      <div class="col-md-2">
        <!--Sidebar content-->

        Search: <input ng-model="query">

      </div>
      <div class="col-md-10">
        <!--Body content-->

        <ul class="phones">
          <li ng-repeat="phone in phones | filter:query">
            {{phone.name}}
            <p>{{phone.snippet}}</p>
          </li>
        </ul>

      </div>
    </div>
  </div>

我們添加了一個(gè)標(biāo)準(zhǔn)HTML<input>元素標(biāo)記,并使用Angular的filter函數(shù)來處理repeat指令的輸入。

這使用戶輸入搜索條件,并在手機(jī)列表中快速看到搜索結(jié)果。新的代碼演示如下:

  • 數(shù)據(jù)綁定:這是Angular的一個(gè)核心功能。當(dāng)網(wǎng)頁載入時(shí),Angular把輸入框的名稱綁定到數(shù)據(jù)模塊的同名的變量上,并保持兩者同步。

    在代碼中,用戶打字到輸入框的數(shù)據(jù)(命名為query)很快可以作為一個(gè)篩選器輸入到列表迭代器(phone in phones | filter:query)中。在改變數(shù)據(jù)模塊的時(shí)候,導(dǎo)致迭代器的輸入發(fā)生變化,迭代器有效地更新了DOM,以反映模塊的當(dāng)前狀態(tài)。

  • 使用filter篩選器:filter函數(shù)使用了query值發(fā)創(chuàng)建一個(gè)新的數(shù)列,只包含匹配query的記錄。

    ngRepeat自動(dòng)更新了視力,以響應(yīng)filter篩選器返回的手機(jī)數(shù)字的變化。該處理對(duì)開發(fā)者來說是完全透明的。

測(cè)試

在第二步中,我們學(xué)會(huì)了如何編寫并運(yùn)行單元測(cè)試。對(duì)于測(cè)試我們的用JavaScript編寫的應(yīng)用程序的控制器和其它組件,單元測(cè)試是完美的,但是測(cè)試DOM操作或測(cè)試我們的應(yīng)用程序的接通不太方便。針對(duì)這些,一個(gè)端到端的測(cè)試是一個(gè)更好的選擇。

該搜索功能完全是通過模板和數(shù)據(jù)綁定來實(shí)現(xiàn)的,我們將編寫我們第一個(gè)端到端的測(cè)試,以驗(yàn)證該功能起了什么作用。

test/e2e/scenarios.js:

describe('PhoneCat App', function() {

  describe('Phone list view', function() {

    beforeEach(function() {
      browser.get('app/index.html');
    });

    it('should filter the phone list as a user types into the search box', function() {

      var phoneList = element.all(by.repeater('phone in phones'));
      var query = element(by.model('query'));

      expect(phoneList.count()).toBe(3);

      query.sendKeys('nexus');
      expect(phoneList.count()).toBe(1);

      query.clear();
      query.sendKeys('motorola');
      expect(phoneList.count()).toBe(2);
    });
  });
});

這個(gè)測(cè)試驗(yàn)證了搜索框以及迭代器是否正確地接通了。注意,在Angular中,編寫端到端測(cè)試是如此地容易。雖然這個(gè)示例只針對(duì)一個(gè)簡單的測(cè)試,但是它確實(shí)很容易測(cè)試任何功能化的、可讀的、端到端的測(cè)試。

利用Protractor運(yùn)行端到端的測(cè)試

甚至雖然測(cè)試的句法看起來很像我們的用Jasmine編寫的控制器單元測(cè)試,但是端到端測(cè)試使用Protractor的API。在http://angular.github.io/protractor/#/api可以讀到Protractor的API。

與Karma很像的是針對(duì)單元測(cè)試的測(cè)試運(yùn)行者,我們使用Protractor以運(yùn)行端到端測(cè)試。用npm run protractor來嘗試它。端到端測(cè)試很慢,所以與單元測(cè)試不同,在運(yùn)行測(cè)試之后Protractor將退出,不會(huì)自動(dòng)在每次文件更改時(shí)重新運(yùn)行測(cè)試套裝。要想重新運(yùn)行測(cè)試套裝,需要再次執(zhí)行npm run protractor。

注意,你必須確保你的應(yīng)用通過一個(gè)web服務(wù)器提供服務(wù),從而用Protractor測(cè)試。你可以使用`npm start`來做到這。你還需要確保你在運(yùn)行`npm run protractor`之前已經(jīng)安裝了Protractor,并更新了web驅(qū)動(dòng)器。You can do this by issuing `npm install` and `npm run update-webdriver` into your terminal.

實(shí)驗(yàn)

顯示當(dāng)前查詢

通過添加一個(gè)綁定到index.html模板的{{query}}來顯示query模塊當(dāng)前的值,并看到當(dāng)你在輸入框中打字時(shí),它如何變化。

在標(biāo)題中顯示查詢

讓我們看到我們可以取得query模板的當(dāng)前值,模塊出現(xiàn)在HTML網(wǎng)頁的標(biāo)題上。

  • 把一個(gè)端到端測(cè)試添加到describe塊中,test/e2e/scenarios.js看起來將如這:

      describe('PhoneCat App', function() {
    
        describe('Phone list view', function() {
    
          beforeEach(function() {
            browser.get('app/index.html');
          });
    
          var phoneList = element.all(by.repeater('phone in phones'));
          var query = element(by.model('query'));
    
          it('should filter the phone list as a user types into the search box', function() {
            expect(phoneList.count()).toBe(3);
    
            query.sendKeys('nexus');
            expect(phoneList.count()).toBe(1);
    
            query.clear();
            query.sendKeys('motorola');
            expect(phoneList.count()).toBe(2);
          });
    
          it('should display the current filter value in the title bar', function() {
            query.clear();
            expect(browser.getTitle()).toMatch(/Google Phone Gallery:\s*$/);
    
            query.sendKeys('nexus');
            expect(browser.getTitle()).toMatch(/Google Phone Gallery: nexus$/);
          });
        });
      });

    運(yùn)行protractor(npm run protractor),看到測(cè)試失敗了。

  • 你可能認(rèn)為你只需要用以下方式向標(biāo)題標(biāo)簽添加{{query}}

    <title>Google Phone Gallery: {{query}}</title>

    然而,當(dāng)你重載入這個(gè)網(wǎng)頁的時(shí)候,你不會(huì)看到想要的結(jié)果。這是因?yàn)椤安樵儭蹦K駐留在作用域內(nèi),由ng-controller="PhoneListCtrl"指令在body元素上定義。

    <body ng-controller="PhoneListCtrl">

    如果你想要從<title>元素上綁定查詢模塊,你必須把ngController聲明移動(dòng)到HTML元素上,因?yàn)樗莃ody元素和title元素常用的父元素。

    <html ng-app="phonecatApp" ng-controller="PhoneListCtrl">

    確保從body元素中移除ng-controller聲明。

  • 重新運(yùn)行rpm run protractor,看到現(xiàn)在測(cè)試已經(jīng)看通過了。

  • 在title元素內(nèi)部使用雙花工作得很好,與此同時(shí),你可能會(huì)注意到頁面加載的一瞬間它們確實(shí)顯示給用戶了。一個(gè)更好的解決方案是使用ngBind指令ngBindTemplate指令,當(dāng)頁面加載時(shí)用戶能看到它們。

    <title ng-bind-template="Google Phone Gallery: {{query}}">Google Phone Gallery</title>

總結(jié)

我們現(xiàn)在已經(jīng)把全文搜索添加上去了,還包含了一個(gè)用來驗(yàn)證搜索是否起作用的測(cè)試!現(xiàn)在讓我們前往第四步 雙路數(shù)據(jù)綁定以學(xué)會(huì)如何向手機(jī)應(yīng)用添加排序功能。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)