NG筆記29-下拉選單連動
13 | 21,367 |
跟同事討論到下拉選單連動(最常見的經典應用是縣市、行政區下拉選單連動,選取縣市後自動換成該縣市的行政區清單),這才發現針對這門必修課,我只寫過KO版範例,沒寫過NG版,趕緊補上。
我寫了一個三層式下拉選單連動範例,在ViewModel中安排Level1、Level2、Level3三個屬性保存下拉選單選取結果,另外用L1Options、L2Options、L3Options分別存放Level1-3的下拉選單選項。透過$scope.$watch(),在Level1變動時更新第二層選項,在Level1或Level2變動時更新第三層選項。更新選項時,若Level2/Level3的值不在選項中,則自動切到第一個選項。
為驗證反向操作,我還做了一個修改Level1、Level2、Level3值的按鈕,測試修改資料後下拉選單是否能正確對應。
排版顯示純文字
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>linked dropdowns</title>
<style>
body { font-size: 9pt; }
div { padding: 6px; }
</style>
</head>
<body ng-controller="main">
<div>
<select ng-model="m.Level1" ng-options="o as o for o in m.L1Options"></select>
<select ng-model="m.Level2" ng-options="o as o for o in m.L2Options"></select>
<select ng-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>
<select ng-model="m.Path" ng-options="o as o for o in m.PathOptions"></select>
<button ng-click="m.SetLevels()">Set Levels</button>
</div>
<script src="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
Comments
# by 機密
如果是包在物件內,像是這樣的概念L1{L2[{L3[]}]} 那也可以用filter的方式進行過濾 缺點是第一次下來的清單會比較大 優點是寫的比較少XDDD
# by Alison
版主您好: 冒昧打擾了~~我是松崗圖書的編輯黃小姐。在網路上看到您的網站上有許多分享技術的文章。不曉得您是否有想要撰寫書籍的想法呢?若您對於撰寫書籍有興趣,但是有其他比較偏好的主題,都歡迎分享看法。alisonhuang@kingsinfo.com.tw 希望能有機會合作書籍。 靜待佳音
# by Neal
請問如果是四層連動, 模擬資料那邊, 格式要怎麼寫? 謝謝!
# by Jeffrey
to Neal, 差不多像這樣吧:https://gist.github.com/darkthread/630f2a777a97748edff0b4412bae61ef
# by Neal
非常感謝您的回覆! 我用您的code來做這個功能, 但不知道問題出在哪? http://jsbin.com/soqalamenu/edit?html,js,output 麻煩您解惑了
# by Jeffrey
to Neal, Check it out! http://jsbin.com/tokoxul/1/edit?html,js,output
# by Neal
太感謝了!
# by Neal
不好意思, 我看了很久還是不知道, 我哪邊寫不對...
# by Jeffrey
to Neal, 不確定你是否有貼錯連結,你的版本只有第一個TD放了SELECT,後三個都是{{m.Level*}}。而資料連動的部分錯在self.L3Options = data[self.Level1] && data[self.Level1][self.Level2] ? Object.keys(data[self.Level1][self.Level2]) : []; 取第三層時仍要用Object.keys而不是直接當成陣列取用。
# by Neal
沒有貼錯連結, 其實我是想要做這種功能 http://jsbin.com/kakevoguki/edit?html,js,output 以連結來說 第一欄位的 第一個對應西瓜 第二個對應火龍果 第三個對應蘋果 第二欄位可以隨著select改變, 把值show在第三第四第五欄位 只是現在變成全部都西瓜...
# by Neal
http://jsbin.com/bugoqudojo/edit?html,js,output 後來我改用別種方式 只是要預設顯示option第一個 這個就難倒我了
# by Jeffrey
to Neal, 若是第二欄位隨select改變, 值show在第三第四第五欄位,資料設三層就好,第三層放陣列。至於最後的寫法,預設option未選第一個因為存成物件屬性走(key,value)的限制多,我會改成物件陣列:http://jsbin.com/gutural/1/edit?html,js,output
# by Neal
請問像您這樣寫 http://jsbin.com/gutural/1/edit?html,js,output 要抓值的話, 是要怎麼設定值?