基于Angular创建后台数据模拟(译)
我們已經(jīng)習(xí)慣用AngularJS來創(chuàng)建前后端分離的應(yīng)用,同時為了便于開發(fā)也會通過在前端代碼庫中使用mock數(shù)據(jù)來模擬服務(wù)端的接口。使用mock數(shù)據(jù)具有以下諸多的好處:
* 如果你并不是接口api的開發(fā)者,使用mock數(shù)據(jù)你就不用等待接口api設(shè)計完成就可以開始本地開發(fā) * 如果你自己開發(fā)接口的api,使用mock數(shù)據(jù)不僅可以讓你更專注于前端開發(fā),還不比糾結(jié)于后端具體的細節(jié)實現(xiàn) * 你可以快速的開發(fā)內(nèi)容而不用管后臺邏輯 * 建立mock服務(wù)還可以幫助你設(shè)計接口api的結(jié)構(gòu) * mock數(shù)據(jù)服務(wù)還可以給其他angular組件在對應(yīng)服務(wù)上做單元測試用本文我們介紹的是ngMockE2E模塊提供的$httpBackend服務(wù)。需要注意的是它跟ngMock模塊提供的同名服務(wù)是不同的哦~這兩個$httpBackend服務(wù)連api都極為相似,但是ngMock版的$httpBackend主要用來做單元測試,因此它額外增加了很多測試用例和調(diào)用的功能在里面。我們今天要介紹的這個ngMockE2E則是針對angular應(yīng)用開發(fā)中后端數(shù)據(jù)mock功能。
$httpBackend使用ngResource($resource)的resources給我們提供了一個mock終端。它可以應(yīng)用到所有的http方法并返回特殊的句柄--例如:GET,POST,DELETE等等。它有效的取代了$http在Angular中的服務(wù)棧,因此它具有穿越的特性,無服務(wù)的請求可以直接穿越到服務(wù)端。它使得我們可以在靜態(tài)服務(wù)器上創(chuàng)建包涵了所有服務(wù)的完美應(yīng)用。
接下來我們先不急于開發(fā)一個完整的Angular應(yīng)用,先從怎樣開發(fā)簡單的后段CRUD功能入手。這里我們首先開發(fā)如下功能:
* List - Resource.query() * Create - Resource.save() or resource.$save() * Get - Resource.get() * Update - Resource.update() or resource.$update() * Delete/remove - Resource.remove or resource.$remove()例子中用到的所有代碼都可以從這里點我啊得到。
多余的事情不說,我們現(xiàn)在就開始。從Angular的模版開始,先聲明app module并加入項目需要依賴的模塊。
var app = angular.module('app', ['ngResource','ngMockE2E' ]);然后在定義一個提供Angular組件和后端mock數(shù)據(jù)的接口服務(wù)的Contract resources。
app.factory('Contact', ['$resource', function($resource) {return $resource('/contacts/:id',{id: '@id'},{'update': {method: 'PUT'}}); }]);完成Contact resources的定義我們就可以開始定義mock backend了。$httpBackend其實是通過一個run模塊來定義的,在我們的例子中我們把它添加到app的run模塊中,然后定義一組contacts。
app.run(['$httpBackend', function($httpBackend) {contacts = [{id: 1,name: 'Ada Lovelace',phone: '8445551815'},{id: 2,name: 'Grace Hopper',phone: '8445551906'},{id: 3,name: 'Charles Babbage',phone: '8445556433'}];// $httpBackend interactions are defined here... }]);這個contacts數(shù)組是mock backend的所有操作都可以訪問的,就像一個數(shù)據(jù)倉庫,這是創(chuàng)建mock數(shù)據(jù)倉庫的一種方式。另一種方式是創(chuàng)建一個以resources的id為下標(biāo)的關(guān)聯(lián)數(shù)組。另外為了簡單和條理清晰我們還要定義一些數(shù)組查找和操作的基礎(chǔ)方法,不想這么麻煩就直接用underscore或者lodash。
我們先模擬一個最簡單的通訊錄接口,用get方式請求/contacts就返回整個通訊錄。
// Query; returns all contacts. $httpBackend.whenGET('/contacts').respond(contacts);再來實現(xiàn)Contact.save方法。ngResource的對應(yīng)方法可以發(fā)送一個攜帶通訊錄數(shù)據(jù)的post請求,這樣后端就會增加一條新的紀錄。
// Save; create a new contact. $httpBackend.whenPOST('/contacts').respond(function(method, url, data) {var newContact = angular.fromJson(data);contacts.push(newContact);return [200, newContact, {}]; });因為angular組件會把數(shù)據(jù)當(dāng)作json來處理且不會復(fù)查,所以一定要注意將序列化的通訊錄數(shù)據(jù)轉(zhuǎn)成json。創(chuàng)建一條新的紀錄就像在contacts數(shù)組push一條數(shù)據(jù)一樣簡單。
獲取一條通訊錄數(shù)據(jù)相對就比較麻煩了,我們必須做兩件事:從請求url中提取ID;從關(guān)聯(lián)數(shù)組中查找到這個ID。代碼如下:
// Get; return a single contact. $httpBackend.whenGET(/\/contacts\/(\d+)/, undefined, ['id']).respond(function(method, url, data, headers, params) {var contact = findContactById(params.id);if (contact == null) {return [404, undefined, {}];}return [200, contact, {}]; });我們用一個正則匹配url,獲取到id的集合。angular把匹配的到的結(jié)果保存到params的id屬性上,也就是whenGET方法的第三個入?yún)ⅰT僮トミ@個值傳到findContactById方法中,將查詢的結(jié)果返回給我們。最后,我們返回查詢結(jié)果,如果為空就返回404。
findContactById方法將ID的值轉(zhuǎn)成數(shù)字,過濾數(shù)組找到匹配值并返回。
function findContactById(id) {// Convert id to a number.var contactId = Number(id);var matches = contacts.filter(function(contact) {return contact.id === contactId;});var contact = matches.shift();return contact; }update方法于get方法很相似,區(qū)別只在于怎樣更新通訊錄數(shù)據(jù)。代碼如下:
// Update; change details for an existing contact. $httpBackend.whenPUT(/\/contacts\/(\d+)/, undefined, undefined, ['id']).respond(function(method, url, data, headers, params) {var contact = findContactById(params.id),parsedData = angular.fromJson(data);if (contact == null) {return [404, undefined, {}];}angular.extend(contact, parsedData);return [200, contact, {}]; });成功找到這條數(shù)據(jù)之后再使用angualr.extend方法將更新的數(shù)據(jù)拷貝到contact對象的屬性上。這樣我們不用破壞代碼里相關(guān)的任何引用包括contacts數(shù)組。
最后是delete方法。仍然跟get和put類似,刪除操作仍然依賴于findContactById方法來查找通訊錄。一旦再contact對象中找到它的位置,就使用array#splice刪除掉contact對象中的這條紀錄:
// Delete; remove existing contact. $httpBackend.whenDELETE(/\/contacts\/(\d+)/, undefined, ['id']).respond(function(method, url, data, headers, params) {var contact = findContactById(params.id);if (contact == null) {return [404, undefined, {}];}// Replace contacts array with filtered results, removing deleted contact.contacts.splice(contacts.indexOf(contact), 1);return [200, undefined, {}]; });完成這些后臺服務(wù)和數(shù)據(jù)的定義,我們就可以把整個應(yīng)用跑起來了。整個頁面應(yīng)用的和核心控制器是一個所有服務(wù)功能之行時調(diào)用的簡單事務(wù)。隨著通訊錄的get操作,結(jié)果就會呈現(xiàn)在我們面前。然后使用更新功能給Grace Hopper所在列添加她的聯(lián)系人姓名。創(chuàng)建操作是添加Gloria Gordan Bolotsky到通訊錄。刪除操作是將Charls Babbage從通訊錄刪除。增加,刪除,更新的操作是放在一個promise隊列中,結(jié)果會返回到成功的回調(diào)函數(shù)中。這就是整個控制器做的事情。
app.controller('MainCtrl', function($scope, Contact) {//List$scope.contacts = Contact.query();// Get$scope.ada = Contact.get({id: 1});// UpdateContact.get({id: 2}).$promise.then(function(contact2) {contact2.name = 'Rear Admiral Grace Hopper';return contact2.$update().$promise;}).then(updateContactsList);// Createvar newContact = new Contact({name: 'Gloria Gordon Bolotsky',phone: '8445556433'});newContact.$save().then(updateContactsList);// DeleteContact.remove({id: 3}).$promise.then(updateContactsList);function updateContactsList() {// Refresh contacts list$scope.contacts = Contact.query();} });最后一步創(chuàng)建這個簡單應(yīng)用的視圖部分:
<!DOCTYPE html> <html ng-app="app"><head><meta charset="utf-8" /><title>AngularJS Plunker</title><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-resource.js"></script><script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular-mocks.js"></script><script>document.write('<base href="' + document.location + '" />');</script><link rel="stylesheet" href="style.css" /><script src="app.js"></script></head><body ng-controller="MainCtrl"><p>All contacts:</p><ul><li ng-repeat="contact in contacts">{{ contact.name }}</li></ul><p>Contact 1: {{ ada.name }}</p></body></html>代碼給我們簡單演示了從通訊錄服務(wù)檢索一條聯(lián)系人記錄。頁面中需要引入:angular,ngResource和ngMockE2E幾個文件。
終于完成了!雖然簡單但是可以給我們使用mock模擬CRUD操作到現(xiàn)代web應(yīng)用打下基礎(chǔ)。
原文地址:http://madebymunsters.com/blog/posts/creating-a-mock-backend-in-angular/
祁幽小貴 譯
總結(jié)
以上是生活随笔為你收集整理的基于Angular创建后台数据模拟(译)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深拷贝与浅拷贝(mutableCopy与
- 下一篇: @ModelAttribute运用详解