記事詳細


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

やりたいことは ASP.NET Core MVC の Create ビューで、親 <select> と子 <select> の両方に「新規追加」機能を付け、SweetAlert2 のモーダルフォームで入力 → AJAX で DB 保存 → ページ遷移なしで <select> を更新 ですね。 以下に 完全動作するサンプル構成 を示します。 (親テーブル:PaymentTypes、子テーブル:PaymentMethods)

内容

モデル定義

Csharp
// Models/PaymentType.cs public class PaymentType { public int Id { get; set; } public string Name { get; set; } = string.Empty; public ICollection<PaymentMethod> PaymentMethods { get; set; } = new List<PaymentMethod>(); } // Models/PaymentMethod.cs public class PaymentMethod { public int Id { get; set; } public string Name { get; set; } = string.Empty; public int PaymentTypeId { get; set; } public PaymentType PaymentType { get; set; } }

2. コントローラー(AJAX 用 API エンドポイント付き)

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; } // Create GET public IActionResult Create() { ViewData["PaymentTypeId"] = new SelectList(_context.PaymentTypes, "Id", "Name"); ViewData["PaymentMethodId"] = new SelectList(_context.PaymentMethods, "Id", "Name"); return View(); } // Create POST [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create(Payment payment) { if (ModelState.IsValid) { _context.Add(payment); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } ViewData["PaymentTypeId"] = new SelectList(_context.PaymentTypes, "Id", "Name", payment.PaymentTypeId); ViewData["PaymentMethodId"] = new SelectList(_context.PaymentMethods, "Id", "Name", payment.PaymentMethodId); return View(payment); } // AJAX: 親追加 [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: 子追加 [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 ビュー(SweetAlert2 + AJAX)

Cshtml
@model Payment @{ ViewData["Title"] = "Create Payment"; } <h2>Create Payment</h2> <form asp-action="Create" method="post"> <div class="form-group"> <label asp-for="PaymentTypeId"></label> <div class="input-group"> <select asp-for="PaymentTypeId" class="form-control" asp-items="@(ViewData["PaymentTypeId"] as SelectList)"></select> <button type="button" class="btn btn-outline-primary" id="btnAddPaymentType">+</button> </div> </div> <div class="form-group"> <label asp-for="PaymentMethodId"></label> <div class="input-group"> <select asp-for="PaymentMethodId" class="form-control" asp-items="@(ViewData["PaymentMethodId"] as SelectList)"></select> <button type="button" class="btn btn-outline-primary" id="btnAddPaymentMethod">+</button> </div> </div> <button type="submit" class="btn btn-success">Save</button> </form> @section Scripts { <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> // 親追加 document.getElementById("btnAddPaymentType").addEventListener("click", function () { Swal.fire({ title: '新しい支払タイプ', input: 'text', inputPlaceholder: 'タイプ名を入力', showCancelButton: true, confirmButtonText: '追加', preConfirm: (name) => { if (!name) { Swal.showValidationMessage('名前を入力してください'); return false; } return fetch('@Url.Action("AddPaymentType")', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name }) }) .then(response => { if (!response.ok) throw new Error(response.statusText); return response.json(); }) .catch(error => { Swal.showValidationMessage(`エラー: ${error}`); }); } }).then((result) => { if (result.isConfirmed && result.value) { const select = document.querySelector('[name="PaymentTypeId"]'); const option = new Option(result.value.name, result.value.id, true, true); select.add(option); Swal.fire('追加しました', '', 'success'); } }); }); // 子追加 document.getElementById("btnAddPaymentMethod").addEventListener("click", function () { const paymentTypeId = document.querySelector('[name="PaymentTypeId"]').value; if (!paymentTypeId) { Swal.fire('先に支払タイプを選択してください', '', 'warning'); return; } Swal.fire({ title: '新しい支払方法', input: 'text', inputPlaceholder: '方法名を入力', showCancelButton: true, confirmButtonText: '追加', preConfirm: (name) => { if (!name) { Swal.showValidationMessage('名前を入力してください'); return false; } return fetch('@Url.Action("AddPaymentMethod")', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, paymentTypeId: parseInt(paymentTypeId) }) }) .then(response => { if (!response.ok) throw new Error(response.statusText); return response.json(); }) .catch(error => { Swal.showValidationMessage(`エラー: ${error}`); }); } }).then((result) => { if (result.isConfirmed && result.value) { const select = document.querySelector('[name="PaymentMethodId"]'); const option = new Option(result.value.name, result.value.id, true, true); select.add(option);                     Swal.fire('追加しました', '', 'success

Powered by Froala Editor

添付画像

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