なるほど、やりたいことは ASP.NET Core MVC の Create ビューで、親 <select> に「新規項目」を追加できるようにし、その場で子 <select> にも新規項目を追加し、DB に保存する ということですね。
これは 親子マスタの動的追加 + Ajax 連動 のパターンです。
以下に、完全な実装例 を示します。
(親:PaymentTypes、子:PaymentMethods)
1. モデル定義
// 親テーブル
public class PaymentType
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<PaymentMethod> PaymentMethods { get; set; }
}
// 子テーブル
public class PaymentMethod
{
public int Id { get; set; }
public string Name { get; set; }
public int PaymentTypeId { get; set; }
public PaymentType PaymentType { get; set; }
}
2. コントローラー
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(Enumerable.Empty<SelectListItem>());
return View();
}
// Create POST
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(PaymentMethod model)
{
if (ModelState.IsValid)
{
_context.PaymentMethods.Add(model);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Create));
}
ViewData["PaymentTypeId"] = new SelectList(_context.PaymentTypes, "Id", "Name", model.PaymentTypeId);
ViewData["PaymentMethodId"] = new SelectList(_context.PaymentMethods.Where(m => m.PaymentTypeId == model.PaymentTypeId), "Id", "Name", model.Id);
return View(model);
}
// Ajax: 親選択時に子を取得
[HttpGet]
public async Task<IActionResult> GetMethods(int paymentTypeId)
{
var methods = await _context.PaymentMethods
.Where(m => m.PaymentTypeId == paymentTypeId)
.Select(m => new { m.Id, m.Name })
.ToListAsync();
return Json(methods);
}
// Ajax: 親の新規追加
[HttpPost]
public async Task<IActionResult> AddPaymentType(string name)
{
if (string.IsNullOrWhiteSpace(name))
return BadRequest("Name is required");
var type = new PaymentType { Name = name };
_context.PaymentTypes.Add(type);
await _context.SaveChangesAsync();
return Json(new { id = type.Id, name = type.Name });
}
// Ajax: 子の新規追加
[HttpPost]
public async Task<IActionResult> AddPaymentMethod(int paymentTypeId, string name)
{
if (string.IsNullOrWhiteSpace(name))
return BadRequest("Name is required");
var method = new PaymentMethod { PaymentTypeId = paymentTypeId, Name = name };
_context.PaymentMethods.Add(method);
await _context.SaveChangesAsync();
return Json(new { id = method.Id, name = method.Name });
}
}
3. Create.cshtml
@model PaymentMethod
@{
ViewData["Title"] = "Create Payment Method";
}
<h2>Create Payment Method</h2>
<form asp-action="Create" method="post">
<div class="form-group">
<label asp-for="PaymentTypeId"></label>
<select asp-for="PaymentTypeId" class="form-control"
asp-items="@(ViewData["PaymentTypeId"] as SelectList)" id="PaymentTypeId">
<option value="">-- Select --</option>
</select>
<button type="button" id="btnAddType" class="btn btn-sm btn-primary mt-1">+ 新規項目</button>
</div>
<div class="form-group">
<label asp-for="Name">Payment Method</label>
<select asp-for="Id" class="form-control"
asp-items="@(ViewData["PaymentMethodId"] as SelectList)" id="PaymentMethodId">
<option value="">-- Select --</option>
</select>
<button type="button" id="btnAddMethod" class="btn btn-sm btn-primary mt-1">+ 新規項目</button>
</div>
<button type="submit" class="btn btn-success">Save</button>
</form>
@section Scripts {
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// 親変更時に子を取得
$("#PaymentTypeId").change(function () {
var typeId = $(this).val();
$("#PaymentMethodId").empty().append('<option value="">-- Select --</option>');
if (typeId) {
$.getJSON('/Payments/GetMethods', { paymentTypeId: typeId }, function (data) {
$.each(data, function (i, item) {
$("#PaymentMethodId").append($('<option>', { value: item.id, text: item.name }));
});
});
}
});
// 親の新規追加
$("#btnAddType").click(function () {
var name = prompt("新しい支払いタイプ名を入力してください:");
if (name) {
$.post('/Payments/AddPaymentType', { name: name }, function (data) {
$("#PaymentTypeId").append($('<option>', { value: data.id, text: data.name, selected: true }));
$("#PaymentTypeId").trigger("change");
});
}
});
// 子の新規追加
$("#btnAddMethod").click(function () {
var typeId = $("#PaymentTypeId").val();
if (!typeId) {
alert("先に支払いタイプを選択してください。");
return;
}
var name = prompt("新しい支払い方法名を入力してください:");
if (name) {
$.post('/Payments/AddPaymentMethod', { paymentTypeId: typeId, name: name }, function (data) {
$("#PaymentMethodId").append($('<option>', { value: data.id, text: data.name, selected: true }));
});
}
});
</script>
}
4. 実装ポイント
- 親
<select> に「+ 新規項目」ボタンを付け、prompt() で名前を入力 → Ajax で DB 保存 → <select> に即反映。 - 子
<select> も同様に「+ 新規項目」ボタンを付け、選択中の親 ID と一緒に Ajax 送信。 - 親変更時に Ajax で子リストを再取得。
- DB 保存はコントローラーの `AddPayment
Powered by Froala Editor