使用 AngularJS 和 Web API 实现的单页应用程序,并使用 Bootstrap 进行响应式设计。






4.81/5 (22投票s)
本文介绍了 AngularJS JavaScript 框架,并展示了如何使用它来开发单页应用程序。
目录
什么是 AngularJS?
AngularJS 是一个结构化的 JavaScript 框架,用于构建单页应用程序 (SPA)。AngularJS 是一个完整的客户端框架,提供了几乎所有的服务,如数据绑定、模板、路由、验证、测试、依赖注入和 CRUD 操作的资源等。
AngularJS 使用的设计模式
AngularJS 使用 MVC 设计模式来组织代码。在 MVC 中,数据和代码被分离成三个组件:模型 (Model)、视图 (View) 和控制器 (Controller)。
模型包含应用程序数据。例如
var products = [
{'name': 'Product 1',
'description': 'Description of Product 1'},
{'name': 'Product 2',
'description': 'Description of Product 2'},
{'name': 'Product 3',
'description': 'The 'Description of Product 3'}
];
视图包含带有声明式数据绑定的 HTML
<ul>
<li ng-repeat="product in products">
<span>{{product.name}}</span>
<p>{{product.description}}</p>
</li>
</ul>
控制器用作模型和视图之间的中介。它包含数据模型和事件处理程序。例如
productApp.controller('ProductListCtrl', function ($scope) {
$scope.price=100;
$scope.AddProduct= function(product)
{
//code goes here
};
});
Angularjs 中的双向数据绑定
AngularJS 最强大的特性之一是双向数据绑定。在双向数据绑定中,如果用户更改了 UI 值,AngularJS 会自动更新底层数据模型。反之,如果底层数据模型发生更改,Angular 会自动更新 UI。这减少了更新 DOM 的代码编写量。
下图展示了双向数据绑定
路由
通过路由,我们可以将 Index 页划分为多个视图模板,并可以在浏览器中为不同的视图模板添加书签。对于路由,Angular 使用其内置的 "ngRoute
" 模块和 $routeProvider 提供程序。示例项目的路由配置如下所示。
var productcatApp = angular.module('productcatApp', [
'ngRoute',
'productcatControllers',
'productcatServices'
]);
productcatApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/products', {
templateUrl: 'Home/ProductList',
controller: 'ProductListCtrl'
}).
when('/products/:productId', {
templateUrl: 'Home/ProductDetail',
controller: 'ProductDetailCtrl'
}).
when('/productNew', {
templateUrl: 'Home/ProductNew',
controller: 'ProductNewCtrl'
}).
when('/productUpdate/:productId', {
templateUrl: 'Home/ProductUpdate',
controller: 'ProductUpdateCtrl'
}).
otherwise({
redirectTo: '/products'
});
}]);
对于每个路由,都有一个 Web API URL 用于提取视图模板,以及一个控制器用于将数据绑定到提取的模板。
带说明的示例项目
说明:本示例项目演示了如何从产品列表中显示、添加、编辑和删除产品。
本示例项目的数据库图如下所示。
索引页
Index 页用作主页,其中包含一个容器,该容器始终使用调用的模板进行更新。
<div id="contentWrapper">
<div class="container">
<div ng-view></div>
</div>
</div>
当用户路由到新 URL 时,带有 Angular 指令 ng-view
的 div
的内容将被新的 HTML 模板替换。
示例项目执行以下步骤。
步骤 1:显示产品列表
下面显示了显示产品列表的 HTML 模板。文件 ProductList.cshtml 包含服务器上的此模板。
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
<button class="btn btn-primary btn-lg btn-block" ng-click="newProduct()">New</button>
</div>
</div>
<div class="row" ng-repeat="product in products">
<div class="col-xs-6 col-sm-8 col-md-8 col-lg-8">
<a href="#/products/{{product.id}}">{{product.name}}</a>
</div>
<div class="hidden-xs col-sm-1 col-md-1 col-lg-1">
<a href="#/products/{{product.id}}"><img class="img-thumbnail img-responsive"
ng-src="{{product.imageUrl}}"/></a>
</div>
<div class="col-xs-3 col-sm-2 col-md-2 col-lg-2">
<a class="btn btn-large btn-success" href="#/productUpdate/{{product.id}}">Update</a>
</div>
<div class="col-xs-3 col-sm-2 col-md-2 col-lg-2">
<button class="btn btn-large btn-success"
ng-click="deleteProduct(product)">Delete</button>
</div>
</div>
在上述模板中,使用 ng-repeat="product in products"
来循环 products
列表,使用 {{product.name}}
语法进行双向数据绑定。并且使用 class="col-xs-6 col-sm-6 col-md-6 col-lg-6"
语法用于 Bootstrap。
调用此模板的路由部分是
when('/products', {
templateUrl: 'Home/ProductList',
controller: 'ProductListCtrl'
})
当请求 URL https:///#/products 时,Angular 会向 Web API URL 'Home/ProductList' 发送 Ajax 请求以获取新的 HTML 模板,返回后 Angular 将控制器 'ProductListCtrl
' 与新模板进行数据绑定。
此模板的控制器是
var productcatControllers = angular.module('productcatControllers', []);
productcatControllers.controller('ProductListCtrl', ['$scope', '$routeParams', '$location',
'$route', 'productService',
function ($scope, $routeParams, $location, $route, productService) {
productService.query(function (data) {
$scope.products = data;
});
$scope.deleteProduct = function (product) {
debugger;
productService.delete({ id: product.id }, function () {
$route.reload();
});
}
$scope.newProduct = function () {
$location.path('/productNew');
}
}]);
这里,Angular Resource 模块用于从服务器提取数据并从服务器删除产品。这里,newProduct()
函数用于重定向到新产品添加页面。
Resource 模块的配置是
var phonecatServices = angular.module('productcatServices', ['ngResource']);
phonecatServices.factory("productService", function ($resource) {
return $resource(
"/api/Product/:id",
{ id: "@id" },
{
"update": { method: "PUT" }
}
);
});
上述语句创建了一个名为 productService
的服务,并将 $resource
服务作为参数传递,该服务用于数据库操作。
服务器端 Web API 代码是
public HttpResponseMessage GetProducts()
{
var collection = db.Products.Select(x => new
{
id = x.id,
name = x.name,
imageUrl = x.imageUrl
});
var yourJson = new JavaScriptSerializer().Serialize(collection);
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(yourJson, Encoding.UTF8, "application/json");
return response;
}
步骤 2:添加新产品
服务器上的 ProductNew.cshtml 页面包含此 UI 的 HTML 模板。
调用此模板的路由部分是
when('/productNew', {
templateUrl: 'Home/ProductNew',
controller: 'ProductNewCtrl'
})
此模板的控制器是
productcatControllers.controller('ProductNewCtrl', ['$scope', '$routeParams', '$location',
'productService',
function ($scope, $routeParams, $location, productService) {
$scope.product = { name: "", imageUrl: "", ProductDetail: { number: 0, price: 0.0,
description: "", companyName: "" } };
$scope.addNewProduct = function (product) {
productService.save(product, function () {
$location.path('/products');
});
}
$scope.cancelNewProduct = function () {
$location.path('/products');
}
}]);
在上面的控制器中,使用 productService
服务的 save 函数将产品保存在数据库中,保存后会重定向到产品列表页面。
服务器端 Web API 代码是
public HttpResponseMessage PostProduct(Product product)
{
if (ModelState.IsValid)
{
db.Products.Add(product);
db.ProductDetails.Add(product.ProductDetail);
db.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
步骤 3:编辑产品
服务器上的 ProductUpdate.cshtml 页面包含此 UI 的 HTML 模板。
调用此模板的路由部分是
when('/productUpdate/:productId', {
templateUrl: 'Home/ProductUpdate',
controller: 'ProductUpdateCtrl'
})
此模板的控制器是
productcatControllers.controller('ProductUpdateCtrl', ['$scope', '$routeParams',
'$location', 'productService',
function ($scope, $routeParams, $location, productService) {
productService.get({ id: $routeParams.productId }, function (data) {
$scope.product = data;
});
$scope.updateProduct = function (product) {
var post = productService.get({}, { id: product.id }, function (data) {
debugger;
post.name = product.name;
post.imageUrl = product.imageUrl;
post.ProductDetail.number = product.ProductDetail.number;
post.ProductDetail.price = product.ProductDetail.price;
post.ProductDetail.description = product.ProductDetail.description;
post.ProductDetail.companyName = product.ProductDetail.companyName;
productService.update(post, function () {
$location.path('/products');
});
});
}
$scope.cancelUpdateProduct = function () {
$location.path('/products');
}
}]);
在上面的控制器中,使用 productService
服务的 update
函数更新数据库中的 product
,更新后会重定向到产品列表页面。
服务器端 Web API 代码是
public HttpResponseMessage PutProduct(int id, Product product)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
if (id != product.id)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
Product productEntity =
db.Products.Where(p => p.id == product.id).FirstOrDefault();
productEntity.name = product.name;
productEntity.imageUrl = product.imageUrl;
productEntity.ProductDetail.number = product.ProductDetail.number;
productEntity.ProductDetail.price = product.ProductDetail.price;
productEntity.ProductDetail.description=product.ProductDetail.description;
productEntity.ProductDetail.companyName = product.ProductDetail.companyName;
db.Entry(productEntity).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
步骤 4:显示产品详细信息
服务器上的 ProductDetail.cshtml 页面包含此 UI 的 HTML 模板。
调用此模板的路由部分是
when('/products/:productId', {
templateUrl: 'Home/ProductDetail',
controller: 'ProductDetailCtrl'
})
此模板的 Controller
是
productcatControllers.controller('ProductDetailCtrl', ['$scope', '$routeParams',
'$location', 'productService',
function ($scope, $routeParams, $location, productService) {
productService.get({ id: $routeParams.productId }, function (data) {
$scope.product = data;
});
$scope.backToProduct = function () {
$location.path('/products');
}
}]);
在上面的控制器中,使用 productService
服务的 get
函数通过 id 从数据库提取产品,并将数据分配给产品 Model
。
服务器端 Web API 代码是
public HttpResponseMessage GetProduct(int id)
{
var product = db.Products.Include("ProductDetail").Where(p => p.id == id).Select(x => new
{
id = x.id,
name = x.name,
imageUrl = x.imageUrl,
ProductDetail = new { id = x.ProductDetail.id, number = x.ProductDetail.number,
price = x.ProductDetail.price,
description = x.ProductDetail.description,
companyName = x.ProductDetail.companyName }
}).FirstOrDefault();
var json = new JavaScriptSerializer().Serialize(product);
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(json, Encoding.UTF8, "application/json");
return response;
}
结论
总而言之,如今 Angular 是一个流行的 JavaScript 框架,用于开发单页应用程序。请下载附件的 zip 文件以获取示例项目。运行它需要 VS2012 和 SQL Server 2008。
历史
- 2014年11月21日:初始版本