記事詳細


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

ASP.NET Core MVC : CreateViewの 親<select asp-for="IncomeCategoryId"……> には項目が選択された、“IncomeCategoryId”(int)が既にあります。子<select asp-for="IncomeTypeId" ……> <option value="add">+ 項目を追加</option> を選択したらSweetAlert2 モーダルで新しい項目名を入力 → Ajax でIncomeTypeクラスの“IncomeCategoryId”列に保存する、 一連の方法を教えてください。

内容

OK、やりたいことは ASP.NET Core MVC の Create ビューで親子セレクトボックスを使い、子セレクトで「+ 項目を追加」を選んだら SweetAlert2 モーダルで新しい項目名を入力し、Ajax でサーバーに保存して即反映する という流れですね。

以下に 完全な実装例 を示します。
(SweetAlert2 は CDN で読み込み、jQuery を利用します)

1. モデル定義

Csharp
// IncomeCategory.cs public class IncomeCategory { public int Id { get; set; } public string Name { get; set; } = string.Empty; public ICollection<IncomeType> IncomeTypes { get; set; } = new List<IncomeType>(); } // IncomeType.cs public class IncomeType { public int Id { get; set; } public string Name { get; set; } = string.Empty; // 外部キー public int IncomeCategoryId { get; set; } public IncomeCategory? IncomeCategory { get; set; } }

2. ViewModel

Csharp
public class IncomeCreateViewModel { public int IncomeCategoryId { get; set; } public int? IncomeTypeId { get; set; } public IEnumerable<SelectListItem> IncomeCategories { get; set; } = Enumerable.Empty<SelectListItem>(); public IEnumerable<SelectListItem> IncomeTypes { get; set; } = Enumerable.Empty<SelectListItem>(); }

3. コントローラー

Csharp
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; public class IncomeController : Controller { private readonly ApplicationDbContext _context; public IncomeController(ApplicationDbContext context) { _context = context; } // Create GET public IActionResult Create() { var vm = new IncomeCreateViewModel { IncomeCategories = _context.IncomeCategories .Select(c => new SelectListItem { Value = c.Id.ToString(), Text = c.Name }) .ToList(), IncomeTypes = new List<SelectListItem>() // 初期は空 }; return View(vm); } // Ajax: IncomeCategoryId に紐づく IncomeType を取得 [HttpGet] public IActionResult GetIncomeTypes(int categoryId) { var types = _context.IncomeTypes .Where(t => t.IncomeCategoryId == categoryId) .Select(t => new { t.Id, t.Name }) .ToList(); return Json(types); } // Ajax: 新しい IncomeType を追加 [HttpPost] public IActionResult AddIncomeType([FromBody] AddIncomeTypeRequest request) { if (string.IsNullOrWhiteSpace(request.Name)) return BadRequest("Name is required"); var newType = new IncomeType { Name = request.Name.Trim(), IncomeCategoryId = request.IncomeCategoryId }; _context.IncomeTypes.Add(newType); _context.SaveChanges(); return Json(new { id = newType.Id, name = newType.Name }); } } public class AddIncomeTypeRequest { public int IncomeCategoryId { get; set; } public string Name { get; set; } = string.Empty; }

4. Create.cshtml

Razor
@model IncomeCreateViewModel @{ ViewData["Title"] = "Create Income"; } <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css"> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <form asp-action="Create" method="post"> <div> <label>Category</label> <select asp-for="IncomeCategoryId" asp-items="Model.IncomeCategories" id="categorySelect"></select> </div> <div> <label>Type</label> <select asp-for="IncomeTypeId" id="typeSelect"> <option value="">-- Select Type --</option> <option value="add">+ 項目を追加</option> </select> </div> <button type="submit">Save</button> </form> <script> $(function () { // 親カテゴリ変更時に子タイプをロード $('#categorySelect').on('change', function () { var categoryId = $(this).val(); if (!categoryId) return; $.getJSON('/Income/GetIncomeTypes', { categoryId: categoryId }, function (data) { var $typeSelect = $('#typeSelect'); $typeSelect.empty(); $typeSelect.append('<option value="">-- Select Type --</option>'); $.each(data, function (i, item) { $typeSelect.append('<option value="' + item.id + '">' + item.name + '</option>'); }); $typeSelect.append('<option value="add">+ 項目を追加</option>'); }); }); // 「+ 項目を追加」選択時 $('#typeSelect').on('change', function () { if ($(this).val() === 'add') { var categoryId = $('#categorySelect').val(); if (!categoryId) { Swal.fire('カテゴリを先に選択してください'); $(this).val(''); return; } Swal.fire({ title: '新しいタイプ名を入力', input: 'text', showCancelButton: true, confirmButtonText: '追加', cancelButtonText: 'キャンセル', inputValidator: (value) => { if (!value) { return '名前を入力してください'; } } }).then((result) => { if (result.isConfirmed) { $.ajax({ url: '/Income/AddIncomeType', type: 'POST', contentType: 'application/json', data: JSON.stringify({ incomeCategoryId: parseInt(categoryId), name: result.value }), success: function (data) { // 新しい項目を追加して選択状態にする $('#typeSelect option[value="add"]').before( $('<option>', { value: data.id, text: data.name, selected: true }) ); Swal.fire('追加しました', '', 'success'); }, error: function (xhr) { Swal.fire('エラー', xhr.responseText, 'error'); } }); } else { $('#typeSelect').val(''); } }); } }); }); </script>

5. 流れ

  1. カテゴリ選択 → Ajax で IncomeType を取得して子セレクトに反映
  2. 「+ 項目を追加」選択 → SweetAlert2 モーダルで名前入力
  3. OK → Ajax POST /Income/AddIncomeType で保存
  4. 成功時 → 子セレクトに即追加して選択状態にする

6. 注意点

  • CSRF 対策:Ajax POST 時に RequestVerificationToken を送る設定を追加してください(`[Validate

Powered by Froala Editor

添付画像

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