跟同事討論到下拉選單連動(最常見的經典應用是縣市、行政區下拉選單連動,選取縣市後自動換成該縣市的行政區清單),這才發現針對這門必修課,我只寫過KO版範例,沒寫過NG版,趕緊補上。
我寫了一個三層式下拉選單連動範例,在ViewModel中安排Level1、Level2、Level3三個屬性保存下拉選單選取結果,另外用L1Options、L2Options、L3Options分別存放Level1-3的下拉選單選項。透過$scope.$watch(),在Level1變動時更新第二層選項,在Level1或Level2變動時更新第三層選項。更新選項時,若Level2/Level3的值不在選項中,則自動切到第一個選項。
為驗證反向操作,我還做了一個修改Level1、Level2、Level3值的按鈕,測試修改資料後下拉選單是否能正確對應。
<!DOCTYPEhtml>
<htmlng-app="app">
<head>
<metacharset="utf-8">
<metaname="viewport"content="width=device-width">
<title>linked dropdowns</title>
<style>
body { font-size: 9pt; }
div { padding: 6px; }
</style>
</head>
<bodyng-controller="main">
<div>
<selectng-model="m.Level1"ng-options="o as o for o in m.L1Options"></select>
<selectng-model="m.Level2"ng-options="o as o for o in m.L2Options"></select>
<selectng-model="m.Level3"ng-options="o as o for o in m.L3Options"></select>
</div>
<div>
L1 = {{m.Level1}}, L2 = {{m.Level2}}, L3 = {{m.Level3}}
</div>
<div>
<selectng-model="m.Path"ng-options="o as o for o in m.PathOptions"></select>
<buttonng-click="m.SetLevels()">Set Levels</button>
</div>
<scriptsrc="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script>
function myViewModel(scope) {
var self = this;
self.Level1 = null;
self.Level2 = null;
self.Level3 = null;
//模擬資料
var data = self.Data = {
"台北": {
"文山": [ "政大" ],
"大安": [ "台大", "台科大" ]
},
"新竹": {
"東區": [ "交大", "清大" ]
},
"台南": {
"東區": [ "成大" ],
"官田": [ "南藝" ]
}
};
//各Level對應的選項集合
self.L1Options = Object.keys(self.Data);
self.Level1 = self.L1Options[0];
self.L2Options = [];
self.L3Options = [];
//Level1變更時連動L2Options
scope.$watch("m.Level1", function() {
self.L2Options = data[self.Level1] ? Object.keys(data[self.Level1]) : [];
//檢查Level2是否在選項中,若無將Level2設定第一筆選項
var idx = $.inArray(self.Level2, self.L2Options);
if (idx == -1) self.Level2 = self.L2Options[0];
});
//Level1或Level2變更時連動L3Options
scope.$watch("m.Level1+'/'+m.Level2", function() {
self.L3Options =
data[self.Level1] && data[self.Level1][self.Level2] ?
data[self.Level1][self.Level2] :
[];
//檢查Level3是否在選項中,若無將Level3設定第一筆選項
var idx = $.inArray(self.Level3, self.L3Options);
if (idx == -1 ) self.Level3 = self.L3Options[0];
});
//產生單層資料,形成下拉選單,用來測試更動Level1/Level2/Level3後連動是否正確
var list = [];
self.L1Options.forEach(function(city) {
Object.keys(data[city]).forEach(function(area) {
data[city][area].forEach(function(school) {
list.push(city + "/" + area + "/" + school);
});
});
});
self.Path = "";
self.PathOptions = list;
//按鈕後修改Level1/Level2/Level3
self.SetLevels = function() {
var p = self.Path.split('/');
self.Level1 = p[0];
self.Level2 = p[1];
self.Level3 = p[2];
};
}
angular.module("app", [])
.controller("main", function ($scope) {
$scope.m = new myViewModel($scope);
});
</script>
</body>
</html>
在實務上,選項可能需要透過AJAX方式取回,此時將兩個$watch()函式改為AJAX查詢邏輯即可。JSBin上有Live Demo,大家可以動手玩玩。
[NG系列]
http://www.darkthread.net/kolab/labs/default.aspx?m=post&t=angularjs