以下は、前回のサンプルを改良した Bootstrapモーダル対応版 の ASP.NET Core MVC 実装例です。
prompt を廃止し、モーダルフォームで新規項目を追加できるようにしています。
これにより UX が向上し、バリデーションや入力補助も行いやすくなります。
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. コントローラ
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(Enumerable.Empty<SelectListItem>());
return View();
}
[HttpPost]
public IActionResult AddPaymentType(string name)
{
if (string.IsNullOrWhiteSpace(name))
return BadRequest("Name is required");
var type = new PaymentType { Name = name.Trim() };
_context.PaymentTypes.Add(type);
_context.SaveChanges();
return Json(new { id = type.Id, name = type.Name });
}
[HttpPost]
public IActionResult AddPaymentMethod(int paymentTypeId, string name)
{
if (string.IsNullOrWhiteSpace(name))
return BadRequest("Name is required");
var method = new PaymentMethod { Name = name.Trim(), PaymentTypeId = paymentTypeId };
_context.PaymentMethods.Add(method);
_context.SaveChanges();
return Json(new { id = method.Id, name = method.Name });
}
[HttpGet]
public IActionResult GetPaymentMethods(int paymentTypeId)
{
var methods = _context.PaymentMethods
.Where(m => m.PaymentTypeId == paymentTypeId)
.Select(m => new { id = m.Id, name = m.Name })
.ToList();
return Json(methods);
}
}
3. Create.cshtml
@model YourNamespace.Models.Payment
<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" data-bs-toggle="modal" data-bs-target="#addTypeModal">+</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" data-bs-toggle="modal" data-bs-target="#addMethodModal">+</button>
</div>
</div>
<!-- 親追加モーダル -->
<div class="modal fade" id="addTypeModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">支払タイプ追加</h5></div>
<div class="modal-body">
<input type="text" id="newTypeName" class="form-control" placeholder="タイプ名">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button>
<button type="button" class="btn btn-primary" id="saveTypeBtn">保存</button>
</div>
</div>
</div>
</div>
<!-- 子追加モーダル -->
<div class="modal fade" id="addMethodModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"><h5 class="modal-title">支払方法追加</h5></div>
<div class="modal-body">
<input type="text" id="newMethodName" class="form-control" placeholder="方法名">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button>
<button type="button" class="btn btn-primary" id="saveMethodBtn">保存</button>
</div>
</div>
</div>
</div>
@section Scripts {
<script>
$(function () {
// 親変更時に子リスト更新
$('#PaymentTypeId').change(function () {
var typeId = $(this).val();
$.getJSON('/Payments/GetPaymentMethods', { paymentTypeId: typeId }, function (data) {
var $method = $('#PaymentMethodId');
$method.empty();
$.each(data, function (i, item) {
$method.append($('<option>', { value: item.id, text: item.name }));
});
});
});
// 親保存
$('#saveTypeBtn').click(function () {
var name = $('#newTypeName').val();
if (!name) return;
$.post('/Payments/AddPaymentType', { name: name }, function (data) {
$('#PaymentTypeId').append($('<option>', { value: data.id, text: data.name, selected: true }));
$('#PaymentTypeId').trigger('change');
$('#addTypeModal').modal('hide');
$('#newTypeName').val('');
});
});
// 子保存
$('#saveMethodBtn').click(function () {
var typeId = $('#PaymentTypeId').val();
if (!typeId) { alert("先に支払タイプを選択してください"); return; }
var name = $('#newMethodName').val();
if (!name) return;
$.post('/Payments/AddPaymentMethod', { paymentTypeId: typeId, name: name }, function (data) {
$('#PaymentMethodId').append($('<option>', { value: data.id, text: data.name, selected: true }));
$('#addMethodModal').modal('hide');
$('#newMethodName').val('');
});
});
});
</script>
}
改良ポイント
- Bootstrapモーダルで新規追加 → 入力UIが改善され、バリデーションも容易
- Ajaxで即DB保存 → 保存後に
<select> に反映し、選択状態に設定 - 親変更時に子リストを自動更新
- 入力欄は
.val('') でリセットし、連続追加も可能
この構成なら、
Powered by Froala Editor