OK、やりたいことは ASP.NET Core MVC の Create ビューで親子セレクトボックスを使い、子セレクトで「+ 項目を追加」を選んだら SweetAlert2 モーダルで新しい項目名を入力し、Ajax でサーバーに保存して即反映する という流れですね。
以下に 完全な実装例 を示します。
(SweetAlert2 は CDN で読み込み、jQuery を利用します)
1. モデル定義
// 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
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. コントローラー
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
@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. 流れ
- カテゴリ選択 → Ajax で IncomeType を取得して子セレクトに反映
- 「+ 項目を追加」選択 → SweetAlert2 モーダルで名前入力
- OK → Ajax POST
/Income/AddIncomeType で保存 - 成功時 → 子セレクトに即追加して選択状態にする
6. 注意点
- CSRF 対策:Ajax POST 時に
RequestVerificationToken を送る設定を追加してください(`[Validate
Powered by Froala Editor