深入浅析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;
})
}])