オフィス狛 開発担当の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.csperformance { get; set; } = null!; } }
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 件のコメント:
コメントを投稿