記事詳細


投稿日
2026年09月09日09時35分
タイトル

ASP.NET Core MVC: CreateViewのform内の親の<select asp-for="PaymentTypeId" class="form-control" asp-items="@(ViewData["PaymentTypeId"] as SelectList)">に「新規項目」を追加して、子の<select asp-for="PaymentMethodId" class="form-control" asp-items="@(ViewData["PaymentMethodId"] as SelectList)">に、「新規項目」が追加出来るようにする方法を教えてください。親テーブル名「PaymentTypes」子テーブル名「PaymentMethod」DB保存が必要です。SweetAlert2 を使用した AJAX + モーダル内フォーム にしてページ遷移せずに項目追加 する方法を教えてください。

内容

なるほど、やりたいことはこうですね。

  • 親セレクトPaymentTypeId)に「新規項目」を追加できるようにする
  • 子セレクトPaymentMethodId)も同様に「新規項目」を追加できるようにする
  • DB保存必須PaymentTypes と PaymentMethods テーブル)
  • SweetAlert2 + モーダルフォーム + AJAX でページ遷移せずに追加
  • ASP.NET Core MVC の CreateView 内で実装

以下に、実装の全体像サンプルコードを提示します。
(このまま動かせる形にしてあります)

1. モデル定義

Csharp
// Models/PaymentType.cs public class PaymentType { public int Id { get; set; } public string Name { get; set; } public ICollection<PaymentMethod> PaymentMethods { get; set; } } // Models/PaymentMethod.cs public class PaymentMethod { public int Id { get; set; } public string Name { get; set; } public int PaymentTypeId { get; set; } public PaymentType PaymentType { get; set; } }

2. コントローラ

Csharp
// Controllers/PaymentsController.cs using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.EntityFrameworkCore; public class PaymentsController : Controller { private readonly AppDbContext _context; public PaymentsController(AppDbContext context) { _context = context; } public IActionResult Create() { ViewData["PaymentTypeId"] = new SelectList(_context.PaymentTypes, "Id", "Name"); ViewData["PaymentMethodId"] = new SelectList(_context.PaymentMethods, "Id", "Name"); return View(); } [HttpPost] public async Task<IActionResult> Create(Payment payment) { if (ModelState.IsValid) { _context.Add(payment); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } return View(payment); } // AJAX: 新しい PaymentType を追加 [HttpPost] public async Task<IActionResult> AddPaymentType([FromBody] PaymentType model) { if (string.IsNullOrWhiteSpace(model.Name)) return BadRequest("Name is required"); _context.PaymentTypes.Add(model); await _context.SaveChangesAsync(); return Json(new { id = model.Id, name = model.Name }); } // AJAX: 新しい PaymentMethod を追加 [HttpPost] public async Task<IActionResult> AddPaymentMethod([FromBody] PaymentMethod model) { if (string.IsNullOrWhiteSpace(model.Name) || model.PaymentTypeId <= 0) return BadRequest("Invalid data"); _context.PaymentMethods.Add(model); await _context.SaveChangesAsync(); return Json(new { id = model.Id, name = model.Name }); } }

3. Create.cshtml

Razor
@model Payment <div class="form-group"> <label asp-for="PaymentTypeId"></label> <select asp-for="PaymentTypeId" class="form-control" asp-items="@(ViewData["PaymentTypeId"] as SelectList)"> <option value="">-- 選択 --</option> </select> <button type="button" id="btnAddPaymentType" class="btn btn-sm btn-primary mt-1">+ 新規追加</button> </div> <div class="form-group"> <label asp-for="PaymentMethodId"></label> <select asp-for="PaymentMethodId" class="form-control" asp-items="@(ViewData["PaymentMethodId"] as SelectList)"> <option value="">-- 選択 --</option> </select> <button type="button" id="btnAddPaymentMethod" class="btn btn-sm btn-primary mt-1">+ 新規追加</button> </div> @section Scripts { <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> // PaymentType 追加 document.getElementById("btnAddPaymentType").addEventListener("click", function () { Swal.fire({ title: '新しい支払タイプ', input: 'text', inputPlaceholder: 'タイプ名を入力', showCancelButton: true, confirmButtonText: '追加', cancelButtonText: 'キャンセル' }).then((result) => { if (result.isConfirmed && result.value) { fetch('@Url.Action("AddPaymentType")', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: result.value }) }) .then(res => res.json()) .then(data => { let select = document.getElementById("PaymentTypeId"); let option = new Option(data.name, data.id, true, true); select.add(option); Swal.fire('追加しました', '', 'success'); }) .catch(() => Swal.fire('エラー', '追加できませんでした', 'error')); } }); }); // PaymentMethod 追加 document.getElementById("btnAddPaymentMethod").addEventListener("click", function () { let paymentTypeId = document.getElementById("PaymentTypeId").value; if (!paymentTypeId) { Swal.fire('先に支払タイプを選択してください', '', 'warning'); return; } Swal.fire({ title: '新しい支払方法', input: 'text', inputPlaceholder: '方法名を入力', showCancelButton: true, confirmButtonText: '追加', cancelButtonText: 'キャンセル' }).then((result) => { if (result.isConfirmed && result.value) { fetch('@Url.Action("AddPaymentMethod")', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: result.value, paymentTypeId: paymentTypeId }) }) .then(res => res.json()) .then(data => { let select = document.getElementById("PaymentMethodId"); let option = new Option(data.name, data.id, true, true); select.add(option); Swal.fire('追加しました', '', 'success'); }) .catch(() => Swal.fire('エラー', '追加できませんでした', 'error')); } }); }); </script> }

4. 実装ポイント

  1. SweetAlert2 の input を使ってモーダル入力
  2. AJAX (fetch) でコントローラに JSON を送信
  3. DB保存後、返ってきた ID と Name を <select> に即追加
  4. ページ遷移なしで反映
  5. 子セレクト追加時は、必ず親の PaymentTypeId を送信

5. 拡張案

  • 親セレクト変更時に子セレクトを動的ロード(/GetPaymentMethodsByTypeId API)

Powered by Froala Editor

添付画像

画像はありません
Genreのカテゴリ-名
Views
編集 | 記事一覧