オフィス狛 開発担当のnagoです。
今回は、最近初めて使用したC#(ASP.NET Core MVC)で、
なるほどなぁと思ったモーダル実装についてまとめたいと思います。
DBはPostgreSQL、ビューにはBootstrapを使用しました。
<やりたかったこと>
親画面からボタンクリック
↓
親画面とは別のcshtmlファイルに記述したモーダルを開きつつ、
DBから持ってきたデータをモーダル内に表示させる
<できたもの>
コンサートなどのチケット購入サイト風サンプルを作成してみました。
・Topページ
↓詳細ボタンを押下したら
こんなかんじで表示。
・モーダル
データはこんなかんじ。
処理全体の流れとしては、
①親画面にモーダルのcshtmlを入れ込むためのdivを置いておく
②ボタンが押されたら、ajaxで非同期でコントローラにデータ取得用パラメータを渡す
③コントローラでデータ取得
④取得したデータを成形してビューモデルにセット
⑤コントローラからPertialViewでjsにcshtmlとビューモデルを返却する
⑥モーダル表示
というかんじで作ってみました。
<ソース>
・TopController.cs
using Microsoft.AspNetCore.Mvc;
using DotNetTest.Models;
namespace DotNetTest.Controllers
{
public class TopController : Controller
{
private readonly DotNetTestContext _context;
public TopController(DotNetTestContext context){
this._context = context;
}
[HttpGet]
public IActionResult Top() {
return View(this._context.performance);
}
}
}
・ModalController.cs
using Microsoft.AspNetCore.Mvc;
using DotNetTest.Models;
using System.Linq;
namespace DotNetTest.Controllers
{
public class ModalController : Controller
{
private readonly DotNetTestContext _context;
public ModalController(DotNetTestContext context){
this._context = context;
}
[HttpPost]
public IActionResult ShowModal(ModalViewModel viewModel) {
try
{
if ( viewModel.id != string.Empty && _context.performance != null) {
if( Int32.TryParse( viewModel.id, out int intId )) {
// レコード取得
var performance = _context.performance.SingleOrDefault(p => p.id == intId);
if (performance != null) {
viewModel.name = performance.name;
viewModel.date = performance.date.ToString("yyyy年MM月dd日 HH:mm");
viewModel.place = performance.place;
viewModel.description = performance.description;
viewModel.errorMessage = string.Empty;
// ビューとビューモデルを返却
return PartialView("Modal", viewModel);
}
}
}
// エラーの場合はエラーメッセージ入りビューモデルを返却
return Json(viewModel);
}
catch (System.Exception)
{
throw;
}
}
}
}
・DotNetTestContext.cs
using Microsoft.EntityFrameworkCore;
using DotNetTest.Models;
namespace DotNetTest.Models
{
public class DotNetTestContext: DbContext
{
public DotNetTestContext(DbContextOptions options) : base(options)
{
}
public DbSet performance { get; set; } = null!;
}
}
・Performance.cs
namespace DotNetTest.Models
{
public class performance
{
public int id { get; set; }
public string name { get; set; } = string.Empty;
public DateTime date { get; set; }
public string place { get; set; } = string.Empty;
public string description { get; set; } = string.Empty;
}
}
・ModalViewModel.cs
using Microsoft.AspNetCore.Mvc;
namespace DotNetTest.Models
{
[BindProperties]
public class ModalViewModel
{
public string id { get; set; } = string.Empty;
public string name { get; set; } = string.Empty;
public string date { get; set; } = string.Empty;
public string place { get; set; } = string.Empty;
public string description { get; set; } = string.Empty;
public string errorMessage { get; set; } = "エラーが発生しました";
}
}
・Top.cshtml
@model IEnumerable<DotNetTest.Models.performance>
@{
ViewData["Title"] = "Top";
}
<!doctype html>
<html lang="ja" >
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" >
</head>
<body>
<table>
<tr>
<td colspan="2">
<p class="error_message" id="error_message"></p>
</td>
</tr>
@foreach(var item in Model)
{
<tr>
<td>
<p>・ @item.name @item.date.ToString("yyyy年M月d日 HH:mm")〜</p>
</td>
<td class="button_td">
<button type="button" class="btn btn-primary" data-toggle="modal" value="@item.id" onclick="openModal(this.value);">
詳細
</button>
</td>
</tr>
}
</table>
<div id="modal_base"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</body>
</html>
・Modal.cshtml
@using DotNetTest.Models
@model ModalViewModel
<!-- Modal -->
<div class="modal fade" id="modal" tabindex="-1" aria-labelledby="modalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Model.name</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>
公演日時:@Model.date 〜<br>
会場:@Model.place<br>
説明:@Model.description
</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">
予約
</button>
</div>
</div>
</div>
</div>
・site.js
function openModal(id) {
$('#error_message').val('');
// コントローラ名/メソッド名
const url = new URL(window.location.href) + 'Modal/ShowModal';
// パラメータ成形
let form = new FormData();
form.append('id', id);
$.ajax({
url: url,
type: 'POST',
processData: false,
contentType: false,
data: form
}).done(function(data){
const data_stringify = JSON.stringify(data);
const data_json = JSON.parse(data_stringify);
if(data_json.errorMessage != null) {
$('#error_message').append(data_json.errorMessage);
} else {
// 親画面に置いておいたdivに、コントローラから受け取ったモーダルのcshtmlをセットする
$('#modal_base').html(data);
// モーダル表示
$('#modal_base').find('.modal').modal('show');
}
});
}
親画面と子画面(モーダル)のcshtmlを別ファイルで管理したかったのと、
jsファイルも別ファイルで管理したかったということがあり、苦戦したのですが、
これで思い通りの動きに出来た時はすごく嬉しかったです。
もし同じようなことで躓いた方がいらしたら、参考になれば幸いです。
参考URL:
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.mvc.controller.partialview?view=aspnet-mvc-5.2
ASP.NET Core MVC , Bootstrap , C# , jQuery

0 件のコメント:
コメントを投稿