使用 Telerik MVC 元件實現三個下拉選單的依序載入範例
透過 ASP.NET MVC 和 Kendo UI 建立動態且具預設值的下拉選單
主要要點
- 資料模型設計: 定義並建立相關的資料模型,如國家、省份和城市,以支持下拉選單的資料綁定。
- 控制器邏輯: 實作控制器方法來提供下拉選單的資料,並設置各下拉選單的預設值。
- 前端實現: 使用 Telerik 的 DropDownList 元件結合 JavaScript 和 AJAX 來動態載入和更新下拉選單的資料。
一、資料模型設計
首先,我們需要定義三個資料模型來表示下拉選單的資料結構:Country(國家)、State(省份)和City(城市)。這些模型將用於封裝資料並進行資料庫操作。
1. Country 模型
// Models/Country.cs
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
2. State 模型
// Models/State.cs
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
}
3. City 模型
// Models/City.cs
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int StateId { get; set; }
}
二、建立 ViewModel
接下來,建立一個 ViewModel 來封裝所有下拉選單所需的資料。這樣可以方便地在視圖中綁定資料並管理用戶的選擇。
// Models/ViewModel.cs
using System.Collections.Generic;
public class ViewModel
{
public int SelectedCountryId { get; set; }
public IEnumerable<Country> Countries { get; set; }
public int SelectedStateId { get; set; }
public IEnumerable<State> States { get; set; }
public int SelectedCityId { get; set; }
public IEnumerable<City> Cities { get; set; }
}
三、控制器實作
在控制器中,我們需要實作方法來提供下拉選單的資料源,並設置各下拉選單的預設值。
1. 建立 HomeController
// Controllers/HomeController.cs
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
public class HomeController : Controller
{
// 模擬資料來源
private readonly List<Country> _countries = new List<Country>
{
new Country { Id = 1, Name = "台灣" },
new Country { Id = 2, Name = "美國" }
};
private readonly List<State> _states = new List<State>
{
new State { Id = 1, Name = "台北市", CountryId = 1 },
new State { Id = 2, Name = "新北市", CountryId = 1 },
new State { Id = 3, Name = "加利福尼亞", CountryId = 2 },
new State { Id = 4, Name = "紐約", CountryId = 2 }
};
private readonly List<City> _cities = new List<City>
{
new City { Id = 1, Name = "信義區", StateId = 1 },
new City { Id = 2, Name = "大安區", StateId = 1 },
new City { Id = 3, Name = "板橋區", StateId = 2 },
new City { Id = 4, Name = "中和區", StateId = 2 },
new City { Id = 5, Name = "洛杉磯", StateId = 3 },
new City { Id = 6, Name = "舊金山", StateId = 3 },
new City { Id = 7, Name = "曼哈頓", StateId = 4 },
new City { Id = 8, Name = "布魯克林", StateId = 4 }
};
public ActionResult Index()
{
// 設定預設值
int defaultCountryId = 1; // 台灣
int defaultStateId = _states.FirstOrDefault(s => s.CountryId == defaultCountryId)?.Id ?? 0;
int defaultCityId = _cities.FirstOrDefault(c => c.StateId == defaultStateId)?.Id ?? 0;
var model = new ViewModel
{
SelectedCountryId = defaultCountryId,
Countries = _countries,
SelectedStateId = defaultStateId,
States = _states.Where(s => s.CountryId == defaultCountryId),
SelectedCityId = defaultCityId,
Cities = _cities.Where(c => c.StateId == defaultStateId)
};
return View(model);
}
// 供下拉選單動態載入資料的 Action
public JsonResult GetStates(int countryId)
{
var states = _states.Where(s => s.CountryId == countryId).ToList();
return Json(states, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCities(int stateId)
{
var cities = _cities.Where(c => c.StateId == stateId).ToList();
return Json(cities, JsonRequestBehavior.AllowGet);
}
}
2. 解釋控制器邏輯
Index Action: 在載入視圖時,根據預設的
defaultCountryId和defaultStateId,載入相應的省份和城市資料,並將其封裝在 ViewModel 中。GetStates Action: 根據用戶選擇的國家 ID,返回對應的省份資料。
GetCities Action: 根據用戶選擇的省份 ID,返回對應的城市資料。
四、視圖實作
在視圖中,我們將使用 Kendo UI 的 DropDownList 元件來建立三個下拉選單,並使用 JavaScript 來處理下拉選單的變更事件,以動態載入和更新後續的下拉選單資料。
1. 建立 Index.cshtml
<!-- Views/Home/Index.cshtml -->
@model ViewModel
@{
ViewBag.Title = "三個下拉選單依序載入範例";
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="~/Content/kendo/2023.1.314/kendo.default.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-3.6.0.min.js"></script>
<script src="~/Scripts/kendo/2023.1.314/kendo.all.min.js"></script>
</head>
<body>
<div>
<label for="country">國家:</label>
@(Html.Kendo().DropDownList()
.Name("country")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.Countries)
.Value(Model.SelectedCountryId.ToString())
.OptionLabel("選擇國家...")
.Events(e => e.Change("onCountryChange"))
)
</div>
<div>
<label for="state">省份:</label>
@(Html.Kendo().DropDownList()
.Name("state")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.States)
.Value(Model.SelectedStateId.ToString())
.OptionLabel("選擇省份...")
.Events(e => e.Change("onStateChange"))
)
</div>
<div>
<label for="city">城市:</label>
@(Html.Kendo().DropDownList()
.Name("city")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.Cities)
.Value(Model.SelectedCityId.ToString())
.OptionLabel("選擇城市...")
)
</div>
<script>
function onCountryChange() {
var countryId = this.value();
var stateDropdown = $("#state").data("kendoDropDownList");
var cityDropdown = $("#city").data("kendoDropDownList");
if (countryId) {
$.ajax({
type: "GET",
url: "@Url.Action("GetStates", "Home")",
data: { countryId: countryId },
success: function (states) {
stateDropdown.dataSource.data(states);
stateDropdown.value(""); // 清空選擇
cityDropdown.dataSource.data([]); // 清空城市
cityDropdown.value("");
}
});
} else {
stateDropdown.dataSource.data([]);
stateDropdown.value("");
cityDropdown.dataSource.data([]);
cityDropdown.value("");
}
}
function onStateChange() {
var stateId = this.value();
var cityDropdown = $("#city").data("kendoDropDownList");
if (stateId) {
$.ajax({
type: "GET",
url: "@Url.Action("GetCities", "Home")",
data: { stateId: stateId },
success: function (cities) {
cityDropdown.dataSource.data(cities);
cityDropdown.value(""); // 清空選擇
}
});
} else {
cityDropdown.dataSource.data([]);
cityDropdown.value("");
}
}
$(document).ready(function () {
// 初始化時設置預設值
var countryDropdown = $("#country").data("kendoDropDownList");
var stateDropdown = $("#state").data("kendoDropDownList");
var cityDropdown = $("#city").data("kendoDropDownList");
countryDropdown.value(@Model.SelectedCountryId);
stateDropdown.value(@Model.SelectedStateId);
cityDropdown.value(@Model.SelectedCityId);
});
</script>
</body>
</html>
2. 解釋視圖邏輯
HTML 結構: 建立三個下拉選單對應於國家、省份和城市,並使用 Kendo UI 的 DropDownList 元件來進行資料綁定。
JavaScript 函數:
-
onCountryChange:當國家下拉選單的值改變時,透過 AJAX 請求載入對應的省份資料,並清空城市下拉選單。 -
onStateChange:當省份下拉選單的值改變時,透過 AJAX 請求載入對應的城市資料。 -
$(document).ready:頁面載入時,設置下拉選單的預設值。
-
3. 視覺化流程
| 步驟 | 動作 | 結果 |
|---|---|---|
| 1 | 頁面載入,設置國家、省份和城市的預設值 | 下拉選單顯示預設的國家、省份和城市 |
| 2 | 用戶選擇不同的國家 | 透過 AJAX 請求更新省份下拉選單,並清空城市下拉選單 |
| 3 | 用戶選擇不同的省份 | 透過 AJAX 請求更新城市下拉選單 |
五、完整程式碼範例
以下是完整的範例程式碼,結合後端控制器和前端視圖,實現三個下拉選單的依序載入及預設值設置:
1. Controllers/HomeController.cs
// Controllers/HomeController.cs
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
public class HomeController : Controller
{
// 模擬資料來源
private readonly List<Country> _countries = new List<Country>
{
new Country { Id = 1, Name = "台灣" },
new Country { Id = 2, Name = "美國" }
};
private readonly List<State> _states = new List<State>
{
new State { Id = 1, Name = "台北市", CountryId = 1 },
new State { Id = 2, Name = "新北市", CountryId = 1 },
new State { Id = 3, Name = "加利福尼亞", CountryId = 2 },
new State { Id = 4, Name = "紐約", CountryId = 2 }
};
private readonly List<City> _cities = new List<City>
{
new City { Id = 1, Name = "信義區", StateId = 1 },
new City { Id = 2, Name = "大安區", StateId = 1 },
new City { Id = 3, Name = "板橋區", StateId = 2 },
new City { Id = 4, Name = "中和區", StateId = 2 },
new City { Id = 5, Name = "洛杉磯", StateId = 3 },
new City { Id = 6, Name = "舊金山", StateId = 3 },
new City { Id = 7, Name = "曼哈頓", StateId = 4 },
new City { Id = 8, Name = "布魯克林", StateId = 4 }
};
public ActionResult Index()
{
// 設定預設值
int defaultCountryId = 1; // 台灣
int defaultStateId = _states.FirstOrDefault(s => s.CountryId == defaultCountryId)?.Id ?? 0;
int defaultCityId = _cities.FirstOrDefault(c => c.StateId == defaultStateId)?.Id ?? 0;
var model = new ViewModel
{
SelectedCountryId = defaultCountryId,
Countries = _countries,
SelectedStateId = defaultStateId,
States = _states.Where(s => s.CountryId == defaultCountryId),
SelectedCityId = defaultCityId,
Cities = _cities.Where(c => c.StateId == defaultStateId)
};
return View(model);
}
// 供下拉選單動態載入資料的 Action
public JsonResult GetStates(int countryId)
{
var states = _states.Where(s => s.CountryId == countryId).ToList();
return Json(states, JsonRequestBehavior.AllowGet);
}
public JsonResult GetCities(int stateId)
{
var cities = _cities.Where(c => c.StateId == stateId).ToList();
return Json(cities, JsonRequestBehavior.AllowGet);
}
}
2. Models/Country.cs
// Models/Country.cs
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
3. Models/State.cs
// Models/State.cs
public class State
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
}
4. Models/City.cs
// Models/City.cs
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int StateId { get; set; }
}
5. Models/ViewModel.cs
// Models/ViewModel.cs
using System.Collections.Generic;
public class ViewModel
{
public int SelectedCountryId { get; set; }
public IEnumerable<Country> Countries { get; set; }
public int SelectedStateId { get; set; }
public IEnumerable<State> States { get; set; }
public int SelectedCityId { get; set; }
public IEnumerable<City> Cities { get; set; }
}
6. Views/Home/Index.cshtml
<!-- Views/Home/Index.cshtml -->
@model ViewModel
@{
ViewBag.Title = "三個下拉選單依序載入範例";
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title</title>
<link href="~/Content/kendo/2023.1.314/kendo.default.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-3.6.0.min.js"></script>
<script src="~/Scripts/kendo/2023.1.314/kendo.all.min.js"></script>
</head>
<body>
<div>
<label for="country">國家:</label>
@(Html.Kendo().DropDownList()
.Name("country")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.Countries)
.Value(Model.SelectedCountryId.ToString())
.OptionLabel("選擇國家...")
.Events(e => e.Change("onCountryChange"))
)
</div>
<div>
<label for="state">省份:</label>
@(Html.Kendo().DropDownList()
.Name("state")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.States)
.Value(Model.SelectedStateId.ToString())
.OptionLabel("選擇省份...")
.Events(e => e.Change("onStateChange"))
)
</div>
<div>
<label for="city">城市:</label>
@(Html.Kendo().DropDownList()
.Name("city")
.DataTextField("Name")
.DataValueField("Id")
.BindTo(Model.Cities)
.Value(Model.SelectedCityId.ToString())
.OptionLabel("選擇城市...")
)
</div>
<script>
function onCountryChange() {
var countryId = this.value();
var stateDropdown = $("#state").data("kendoDropDownList");
var cityDropdown = $("#city").data("kendoDropDownList");
if (countryId) {
$.ajax({
type: "GET",
url: "@Url.Action("GetStates", "Home")",
data: { countryId: countryId },
success: function (states) {
stateDropdown.dataSource.data(states);
stateDropdown.value(""); // 清空選擇
cityDropdown.dataSource.data([]); // 清空城市
cityDropdown.value("");
}
});
} else {
stateDropdown.dataSource.data([]);
stateDropdown.value("");
cityDropdown.dataSource.data([]);
cityDropdown.value("");
}
}
function onStateChange() {
var stateId = this.value();
var cityDropdown = $("#city").data("kendoDropDownList");
if (stateId) {
$.ajax({
type: "GET",
url: "@Url.Action("GetCities", "Home")",
data: { stateId: stateId },
success: function (cities) {
cityDropdown.dataSource.data(cities);
cityDropdown.value(""); // 清空選擇
}
});
} else {
cityDropdown.dataSource.data([]);
cityDropdown.value("");
}
}
$(document).ready(function () {
// 初始化時設置預設值
var countryDropdown = $("#country").data("kendoDropDownList");
var stateDropdown = $("#state").data("kendoDropDownList");
var cityDropdown = $("#city").data("kendoDropDownList");
countryDropdown.value(@Model.SelectedCountryId);
stateDropdown.value(@Model.SelectedStateId);
cityDropdown.value(@Model.SelectedCityId);
});
</script>
</body>
</html>
六、關鍵實作細節
1. 非級聯載入的優勢
雖然 Kendo UI 提供了 CascadeDropDown 的功能,但在本範例中,我們選擇手動處理下拉選單的資料載入。這提供了更多的控制權,允許我們在特定情況下,例如需要設置預設值或進行特殊資料處理時,更靈活地管理資料載入過程。
2. 預設值的設置
在控制器的 Index Action 中,我們根據預設的 CountryId 和 StateId,載入相應的省份和城市資料。這保證了在頁面初次載入時,所有下拉選單都會顯示正確的預設值。
3. 使用 AJAX 進行資料載入
通過 AJAX 請求,我們可以在用戶選擇不同的國家或省份時,動態更新後續的下拉選單資料。這不僅提高了應用的響應速度,也減少了不必要的頁面刷新。
4. 清空下拉選單的選擇
當國家或省份的選擇改變時,我們需要清空後續下拉選單的選擇和資料,以避免資料不一致或無效的選擇。例如,當用戶更改國家時,省份和城市下拉選單應該被重置。
5. 統一管理視圖的初始化
在 $(document).ready 函數中,我們確保所有下拉選單在頁面載入時都被正確初始化,並設置其預設值。這確保了用戶在進入頁面時,看到的是一致且預期的下拉選單狀態。
6. 可擴展性
此範例的結構易於擴展,如增加更多層級的下拉選單或引入新的資料來源。只需新增相應的模型、控制器方法和視圖邏輯,即可輕鬆擴展功能。
七、結論
通過上述的實作範例,我們展示了如何使用 Telerik MVC 元件,結合 ASP.NET MVC 和 Kendo UI,實現三個下拉選單的依序載入功能,並在載入過程中設置預設值。這種方式不僅提供了靈活的控制權,也提升了用戶體驗,確保資料的一致性和準確性。
此範例適用於多種情境,如地理位置選擇、產品分類選擇等,可根據具體需求進行調整和擴展。
參考資料
Last updated January 29, 2025