使用 Knockout 和 AngularJS 实现级联下拉列表





5.00/5 (2投票s)
如何使用 Knockout 和 AngularJS 实现级联下拉列表。
引言
Knockout和AngularJS是两个流行的使用Model-View-ViewModel(MVVM)设计模式的JavaScript框架。 MVVM有三个组成部分。
模型(Model):服务器端的持久数据。
视图(View):HTML页面。
视图模型(ViewModel):一个表示模型的纯JavaScript对象。
模型和视图模型通常通过AJAX调用同步。 视图模型和视图由JavaScript框架(Knockout或AngularJS)绑定。 当视图元素更改时,视图模型由JavaScript框架自动更新。 当视图模型数据更改时,视图由框架自动更新。 框架会自动同步视图和视图模型,以节省开发人员编写这部分代码。
使用代码
服务器端ASP.NET MVC控制器
在本文中,服务器端使用ASP.NET MVC框架来返回下拉列表数据。
首先,创建两个用户类。
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int CategoryID { get; set; }
}
其次,创建以下用户对象和MVC控制器方法,以返回客户端框架Knockout和AngularJS的数据。
List<Category> lstCat = new List<Category>()
{
new Category() { CategoryID = 1, CategoryName = "Dairy" },
new Category() { CategoryID = 2, CategoryName = "Meat" },
new Category() { CategoryID = 3, CategoryName = "Vegetable" }
};
List<Product> lstProd = new List<Product>()
{
new Product() { ProductID = 1, ProductName = "Cheese", CategoryID = 1 },
new Product() { ProductID = 2, ProductName = "Milk", CategoryID = 1 },
new Product() { ProductID = 3, ProductName = "Yogurt", CategoryID = 1 },
new Product() { ProductID = 4, ProductName = "Beef", CategoryID = 2 },
new Product() { ProductID = 5, ProductName = "Lamb", CategoryID = 2 },
new Product() { ProductID = 6, ProductName = "Pork", CategoryID = 2 },
new Product() { ProductID = 7, ProductName = "Broccoli", CategoryID = 3 },
new Product() { ProductID = 8, ProductName = "Cabbage", CategoryID = 3 },
new Product() { ProductID = 9, ProductName = "Pepper", CategoryID = 3 }
};
public ActionResult GetCategories()
{
return Json(lstCat, JsonRequestBehavior.AllowGet);
}
public ActionResult GetProducts(int intCatID)
{
var products = lstProd.Where(p => p.CategoryID == intCatID);
return Json(products, JsonRequestBehavior.AllowGet);
}
Knockout实现级联下拉列表
首先,创建HTML标记,其中包含Knockout自定义属性,用于两个下拉列表。
<div>
<label for="categoryList">Categories</label>
<select id="categoryList" data-bind="options: categories,
optionsText: 'CategoryName',
optionsValue: 'CategoryID',
value: selectedCategoryID,
optionsCaption: 'Choose a category ...'">
</select>
</div>
<div>
<label for="productList">Products</label>
<select id="productList" data-bind="options: products,
optionsText: 'ProductName',
optionsValue: 'ProductID',
value: selectedProductID,
optionsCaption: 'Choose a product ...'">
</select>
</div>
注意select元素中的data-bind属性。 Knockout使用此属性将视图连接到视图模型。 这是select元素的绑定名称的解释。
options:用于选项标签的对象数组。
optionsText:选项标签的文本。
optionsValue:选项标签的值。
value:select标签的选中值。
optionsCaption:默认第一个选项的文本。 值为未定义。
其次,创建表示级联下拉列表对象的视图模型对象构造函数。
function CascadeDdlViewModel() {
this.categories = ko.observableArray();
this.selectedCategoryID = ko.observable();
this.products = ko.observableArray();
this.selectedProductID = ko.observable();
};
注意顶级Knockout对象ko的observable
和observableArray
函数。 函数observable
使属性被观察到。 如果属性更改,则绑定到该属性的UI也会更改。 另一方面,如果绑定到该属性的UI更改,则该属性也会更改。 函数observableArray
使数组属性被观察到。 请注意,它只使数组对象的添加和删除可观察。 它不会使对象内部的任何属性更改可观察。
第三,添加以下代码以实现级联下拉列表。
$(document).ready(function () {
vm = new CascadeDdlViewModel();
ko.applyBindings(vm);
// Subscribe to category dropdown list change.
vm.selectedCategoryID.subscribe(function (newValue) {
if (newValue !== undefined) {
$.getJSON('/home/GetProducts', { intCatID: newValue }, function (data) {
vm.products(data);
}).fail(function () {
alert('Error getting products!');
});
}
else {
vm.products.removeAll();
vm.selectedProductID(undefined);
}
});
// Get a list of categories.
$.getJSON('/home/GetCategories', null, function (data) {
vm.categories(data);
}).fail(function () {
alert('Error getting categories!');
});
});
代码包装在jQuery DOM就绪函数中,因此在加载网页后调用该代码。 代码首先创建一个视图模型对象。 然后,它调用Knockout applyBindings
函数来激活Knockout,以便它自动同步视图和视图模型。
为了获取第一个下拉列表更改的通知并重新填充第二个下拉列表,使用了显式订阅。 调用视图模型属性selectedCategoryID
的subscribe
函数,以注册其对此观察属性的订阅。 当类别下拉列表选择更改时,绑定到下拉列表值的属性selectedCategoryID
将更改。 当此属性的值更改时,将调用作为subscribe
函数的参数传递的回调函数。 回调函数调用jQuery的getJSON
函数以获取属于新类别的产品数据并更新products
属性值。 当products
属性值更改时,产品下拉列表的选项列表将更新。 Knockout会自动处理这一系列事件。
最后一段代码只是从服务器获取类别列表并填充类别下拉列表。
AngularJS实现级联下拉列表
首先,创建HTML标记,其中包含AngularJS指令,用于两个下拉列表。
<div id="ddlAppSection" ng-app="ddlApp" ng-controller="ddlController">
<h2>Dropdown List Test</h2>
<div>
<label for="categoryList">Categories</label>
<select id="categoryList"
ng-model="selectedCategoryID"
ng-options="c.CategoryID as c.CategoryName for c in categories">
</select>
</div>
<div>
Selected category: {{ selectedCategoryID }}
</div>
<div>
<label for="productList">Products</label>
<select id="productList"
ng-model="selectedProductID"
ng-options="p.ProductID as p.ProductName for p in products">
</select>
</div>
<div>
Selected product: {{ selectedProductID }}
</div>
</div>
自定义属性(例如ng-app)是AngularJS指令。 这是此处使用的指令的解释。
ng-app:应用程序名称。
ng-controller:控制器名称。
ng-model:HTML元素绑定的对象属性名称。
ng-options:select标签内选项标签的数据。
{{}}语法用于AngularJS表达式。
其次,创建以下JavaScript代码以实现级联下拉列表。
var ddlApp = angular.module('ddlApp', []);
ddlApp.controller('ddlController', ['$scope', '$http', function ($scope, $http) {
// Define model properties
$scope.categories = [{ CategoryID: undefined, CategoryName: 'Choose a category ...' }];
$scope.selectedCategoryID = undefined;
$scope.products = [{ ProductID: undefined, ProductName: 'Choose a product ...'}];
$scope.selectedProductID = undefined;
// Get a list of categories
$http.get('/home/GetCategories').then(function (response) {
$scope.categories = response.data;
$scope.categories.unshift({ CategoryID: undefined, CategoryName: 'Choose a category ...' });
}, function (errResponse) {
alert('Error getting categories!');
});
// Watch selected category value change and update products array.
$scope.$watch('selectedCategoryID', function (newValue, oldValue) {
if (newValue !== undefined) {
$http.get('/home/GetProducts', { params: { intCatID: newValue} }).then(function (response) {
$scope.products = response.data;
$scope.products.unshift({ ProductID: undefined, ProductName: 'Choose a product ...' });
$scope.selectedProductID = undefined;
}, function (errResponse) {
alert('Error getting products!');
});
}
else {
$scope.products = [{ ProductID: undefined, ProductName: 'Choose a product ...'}];
$scope.selectedProductID = undefined;
}
});
} ]);
这段代码首先创建一个模块。 然后,它定义一个控制器。 控制器构造函数有两个参数$scope
和$http
。 对象$scope
是绑定到视图的视图模型。 对象$http
是AngularJS服务,用于促进AJAX服务器调用。 方法$watch
监听视图模型属性更改。 在这种情况下,当所选类别ID更改时,将调用$watch
指定的函数。 这会根据新选择的类别ID更新产品下拉列表。 AngularJS自动处理视图模型和视图之间的同步。
关注点
Knockout和AngularJS都帮助Web开发人员创建和维护动态Web应用程序。 我更喜欢AngularJS,因为它拥有更大的开发人员社区。