ASP.NET Core Razor Page 簡易下拉選單連動
0 | 8,447 |
介紹上回提到的 ASP.NET Core Razor Page 下拉選單連動寫法。如果你對 Razor Page 還沒有概念,推薦幾篇文章:
- Hello, Razor Pages! - 重溫 WebForm 的簡約風格
- Razor Pages 實作 Ajax 呼叫
- ASP.NET Core 新增修改刪除(CRUD)介面傻瓜範例 (1)
- ASP.NET Core CRUD 傻瓜範例 (3) - 快速產生清單與新增修改刪除介面
回到主題,目標是要寫出類似以下的下拉選單連動效果。每個主分類有對應的次分類,例如:主分類選「系統開發」,次分類會切換成系統清單;主分類為「請假」時,次分類則換成特休、事假、病假... 等項目。
連動式下拉選單的前端做法很多,但這次我不想不打算動用 Vue.js、Angular 之類的前端框架,計劃對 Razor Page 編輯介面範本簡單加工,靠幾行 jQuery 把它寫出來就好。
在 Visual Studio 點 CRUD 海陸豪華餐自動產生的主分類、次分類欄位原本長這樣:
<div class="form-group">
<label asp-for="TimeSheetEntry.Category" class="control-label"></label>
<input asp-for="TimeSheetEntry.Category" class="form-control" />
<span asp-validation-for="TimeSheetEntry.Category" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TimeSheetEntry.SubCategory" class="control-label"></label>
<input asp-for="TimeSheetEntry.SubCategory" class="form-control" />
<span asp-validation-for="TimeSheetEntry.SubCategory" class="text-danger"></span>
</div>
在前端會以 <input type="text"> 形式呈現,而我們想把兩個欄位改成連動式下拉選單。主分類部分比較簡單,將 input 改成 select,再加上 asp-items="SelectList 物件" 就可以了,在 ASP.NET Core CRUD 傻瓜範例 (4) - 介面客製調整我有試過呼叫 Html.GetEnumSelectList<CRUDExample.Models.StatusFlags>() 產生 asp-items 需要的 SelectList 物件,這次用的分類資料來自上回文章寫好的 FileDataStore,new SelectList(IEnumerable 物件) 即可產生 asp-items 需要的資料來源,我的分類選項 option value 與 text 相同,傳入 string[] 就好,SelectList 還有其他建構式可以指定 value、text 對應屬性。至於次分類由於要在主分類切換時改變選項清單,稍稍複雜一點,要將儲存次分類值的欄位改成 <input type="hidden" >,另外新增 select。於是 .cshtml 的兩個 input 改寫如下:
<div class="form-group">
<label asp-for="TimeSheetEntry.Category" class="control-label"></label>
<select asp-for="TimeSheetEntry.Category" asp-items="Model.CategoryList" class="form-control">
</select>
<span asp-validation-for="TimeSheetEntry.Category" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TimeSheetEntry.SubCategory" class="control-label"></label>
<select id="SubCategory" name="SubCategory" class="form-control">
</select>
<input type="hidden" asp-for="TimeSheetEntry.SubCategory" class="form-control" />
<span asp-validation-for="TimeSheetEntry.SubCategory" class="text-danger"></span>
</div>
連動部分這次我是用 jQuery 寫,主要在主分類下拉選單 change 事件加上邏輯,發出 AJAX 從後端取得該主分類對映的次分類清單,產生次分類下拉選項,若次分類欄位已有值,則要比對符合選項標為己選取,才能反映現有資料狀態。次分類下拉選單的 change 事件則要將選取結果填入次分類 hidden 欄位:
var subCatgSelector = $("#SubCategory");
$("#TimeSheetEntry_Category").change(function () {
$.getJSON("?handler=SubCategories&category=" + $(this).val()).done(function (options) {
subCatgSelector.empty();
var currVal = $("#TimeSheetEntry_SubCategory").val();
for (var i = 0; i < options.length; i++) {
var option = options[i];
var opEl = $("<option></option>").attr("value", option).text(option);
if (currVal == option) opEl.attr("selected", "selected");
opEl.appendTo(subCatgSelector);
}
});
}).change();
subCatgSelector.change(function () {
$("#TimeSheetEntry_SubCategory").val($(this).val());
});
後端部分,主要是在建構式從 DI 取得 FileDataStore 讀取主分類 string[] 及次分類 Dictionar<string, string[]>,並寫了一個 OnGetSubCategories 供前端 AJAX 呼叫傳入主分類查對映次分類項目:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using PTSWeb.Models.Data;
using PTSWeb.Models.Entities;
using PTSWeb.Models.Page;
namespace PTSWeb.Pages.Entry
{
public class CreateModel : PageModelBase
{
private readonly PTSWeb.Models.Data.PtsDbContext _context;
private readonly FileDataStore fileStore;
public CreateModel(PTSWeb.Models.Data.PtsDbContext context, FileDataStore fileStore)
{
_context = context;
this.fileStore = fileStore;
Categories = fileStore.Categories;
SubCategories = fileStore.SubCategories;
}
public IActionResult OnGet()
{
TimeSheetEntry = new TimeSheetEntry() { UserId = this.User.Identity.Name.Split('\\').Last() };
return Page();
}
[BindProperty]
public TimeSheetEntry TimeSheetEntry { get; set; }
public string[] Categories { get; set; }
public Dictionary<string, string[]> SubCategories { get; set; }
public SelectList CategoryList => new SelectList(Categories);
public JsonResult OnGetSubCategories(string category)
{
return new JsonResult(this.SubCategories[category]);
}
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://aka.ms/RazorPagesCRUD.
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Entries.Add(TimeSheetEntry);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
這樣子,個簡易版的 Razor Page 下拉選單連動就完成囉。
Tutorial of using Razor Page and jQuery to build cascading drop-down lists.
Comments
Be the first to post a comment