深入浅析AngularJS和DataModel
AngularJS简介
AngularJS是一个JavaScript框架。它可通过<script>标签添加到HTML页面。
AngularJS通过指令扩展了HTML,且通过表达式绑定数据到HTML。
什么是AngularJS?
AngularJS使得开发现代的单一页面应用程序(SPAs:SinglePageApplications)变得更加容易。
AngularJS把应用程序数据绑定到HTML元素。
AngularJS可以克隆和重复HTML元素。
AngularJS可以隐藏和显示HTML元素。
AngularJS可以在HTML元素"背后"添加代码。
AngularJS支持输入验证。
通常,在AngularJS中使用JSON作为存储数据的模型。我们可能这样在controller中写model:
app.controller('BookController',['$scope',function($scope){ $scope.book={ id:1, name:'', author:'', stores:[ {id:1,name:'',quantity:2}, {id:2,name:'',quantity:2}, ... ] }; }])
在视图中也许这样用到这个model:
<divng-controller="BookController"> <spanng-bind="book.id"></span> <inputtype="text"ng-model="book.name"/> <inputtype="text"ng-model="book.author"/> </div>
当我们需要从服务端获取数据的时候,可能这样写:
app.controller('BookController',['$scope','$http',function($scope,$http){ varbookId=1; $http.get('api/books'+bookId).success(function(bookData){ $scope.book=bookData; }) $scope.deleteBook=function(){ $http.delete('api/books/'+bookId); } $scope.updateBook=function(){ $http.put('api/books/'+bookId,$scope.book); } $scope.getBookImageUrl=function(width,height){ return'our/iamge/service'+bookId+'/width/height'; } $scope.isAvailable=function(){ if(!$scope.book.stores||$scope.book.stores.length===0){ returnfalse; } reutrn$scope.book.stores.some(function(store){ returnstore.quantity>0; }) } }])
在视图中可能这样使用:
<divng-controller="BookController"> <divng-style="{backgroundImage:'url('+getBookImageUrl(100,100)+')'}"></div> <spanng-bind="book.id"></span? <inputtype="text"ng-model="book.name"/> <inputtype="text"ng-model="book.author"/> isavailable:<spanng-bind="isAvailable()?'Yes':'No'"></span> <buttonng-click="deleteBook()">Delete</button> <buttonng-click="updateBook">Update</button> </div>
以上,JSON格式的model只能在BookController中使用,如何在其他controller中也可以使用呢?
--通过factory方式
app.factory('Book',['$http',function($http){ functionBook(bookData){ if(bookData){ this.setData(bookData); } } Book.prototype={ setData:function(bookData){ angular.extend(this,bookData); }, load:function(id){ varscope=this; $http.get('api/books/'+bookId).success(function(bookData){ scope.setData(bookData); }) }, delete:function(bookId){ $http.delete('api/books/'+bookId); }, update:function(bookId){ $http.put('api/books/'+bookId,this); }, getImageUrl:function(width,height){ return'our/image/service/'+this.book.id+'/'+width+'/'+height; }, isAvailable:funciton(){ if(!this.book.stores||this.book.stores.length===0){ returnfalse; } returnthis.book.stores.some(function(store){ returnstore.quantity>0; }) } } returnBook; }])
以上,通过factory的方式创建了类似Book的一个DataModel,现在可以注入到controller中去了。
app.controller('BookController',['$scope','Book',function($scope,Book){ $scope.book=newBook(); $scope.book.load(1); }])
在视图中也会有相应的变化。
<divng-controller="BookController"> <divng-style="{backgroundImage:'url('+book.getImageUrl(100,100)+')'}"></div> <spanng-bind="book.id"></span> <inputtype="text"ng-model="book.name"/> <inputtype="text"ng-model="book.author"/> isabailble:<spanng-bind="book.isAvailabe()?'Yes':'No'"></span> <buttonng-click="book.delete()">Delete</button> <buttonng-click="book.update()">Update</button> </div>
以上,多个controller可以使用同一个有关book的DataModel了,如果多个controller处理同一个有关book的DataModel呢?
app.factory('booksManager',['$http','$q','Book',function($http.$q,Book){ varbooksManager={ _pool:{}, _retrieveInstance:function(bookId,bookData){ varinstance=this._pool[bookId]; if(instance){ instance.setData(bookData); }else{ instance=newBook(bookData); this._pool[bookId]=instance; } returninstance; }, _seach:function(bookId){ reutrnthis_.pool[bookId]; }, _load:function(bookId,deferred){ varscope=this; $http.get('api/books/'+bookId) .success(funciton(bookData){ varbook=scope._retrieveInstance(bookData.id,bookData); deferred.resolve(book); }) .error(function(){ deferred.reject(); }) }, getBook:function(bookId){ vardeferred=$q.defer(); varbook=this._search(bookId); if(book){ deferred.resove(book); }else{ this._load(bookId,deferred); } returndeferred.promise; }, loadAllBooks:function(){ vardeferred=$q.defer(); varscope=this; $http.get('api/books') .success(function(booksArray){ varbooks=[]; booksArray.forEach(function(bookData){ varbook=scope.l_retrieveInstance(bookData.id,bookData); books.push(book); }); deferred.resolve(books); }) .error(function(){ deferred.reject(); }); returndeferred.promise; }, setBook:function(bookData){ varscope=this; varbook=this._search(bookData.id); if(book){ book.setData(bookData); }else{ book=scope._retrieveInstance(bookData); } returnbook; } }; returnbooksManager; }])
Book服务去掉load方法。
app.factory('Book',['$http',function($http){ functionBook(bookData){ if(bookData){ this.setData(bookData): } //Someotherinitializationsrelatedtobook }; Book.prototype={ setData:function(bookData){ angular.extend(this,bookData); }, delete:function(){ $http.delete('ourserver/books/'+bookId); }, update:function(){ $http.put('ourserver/books/'+bookId,this); }, getImageUrl:function(width,height){ return'our/image/service/'+this.book.id+'/width/height'; }, isAvailable:function(){ if(!this.book.stores||this.book.stores.length===0){ returnfalse; } returnthis.book.stores.some(function(store){ returnstore.quantity>0; }); } }; returnBook; }]);
现在,多个controller可以使用同一个booksManager服务。
app.controller('EditableBookController',['$scope','booksManager',function($scope,booksManager){ booksManager.getBook(1).then(function(book){ $scope.book=book; }) }]) .controller('BooksListController',['$scope','booksManager',function($scope,booksManager){ booksManager.loadAllBooks().then(function(books){ $scope.books=books; }) }])