Chat
Ask me anything
Ithy Logo
Sign in to save

使用 Telerik MVC 元件實現三個下拉選單的依序載入範例

透過 ASP.NET MVC 和 Kendo UI 建立動態且具預設值的下拉選單

dynamic dropdown selection taiwan us

主要要點

  • 資料模型設計: 定義並建立相關的資料模型,如國家、省份和城市,以支持下拉選單的資料綁定。
  • 控制器邏輯: 實作控制器方法來提供下拉選單的資料,並設置各下拉選單的預設值。
  • 前端實現: 使用 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. 解釋控制器邏輯

  1. Index Action: 在載入視圖時,根據預設的 defaultCountryId 和 defaultStateId,載入相應的省份和城市資料,並將其封裝在 ViewModel 中。

  2. GetStates Action: 根據用戶選擇的國家 ID,返回對應的省份資料。

  3. 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. 解釋視圖邏輯

  1. HTML 結構: 建立三個下拉選單對應於國家、省份和城市,並使用 Kendo UI 的 DropDownList 元件來進行資料綁定。

  2. 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

AI-assisted research. Sources, methodology and corrections · Source-checked guides and tools · Explore published answers

Ask Ithy AI
Download Article
Delete Article