WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

ASP.NET Core MVC で Bootstrap5 Modal の利用

by WebSurfer 2023年11月11日 10:46

Visual Studio 2022 を使って作成する ASP.NET Core MVC アプリで、データベースのテーブル一覧を表示し、その中の項目を選択すると、その詳細を Bootstrap5 の Modal を利用して表示する方法を書きます。

Bootstrap Modal に詳細を表示

この記事ではターゲットフレームワークを .NET 7.0 としています。.NET 5.0 以前をターゲットフレームワークとして作成したプロジェクトでは Bootstrap のバージョンが異なるので注意してください。

この記事のベースとしたアプリは、Microsoft のチュートリアル「CRUD 機能を実装する」です。そのアプリの Student テーブルのレコード一覧を表示する Index ページと各レコードの詳細を表示する Details ページを使います。

チュートリアルでは、Index ページに一覧表示されている各項目の右横のアクションリンク Details をクリックすると、別ページ Details に遷移し、遷移した Details ページ上で選択した項目の詳細を表示するようになっています。チュートリアルの「Details ビューに登録を追加する」セクションの下の方の画像を見てください。

それを、別ページ Details に遷移しないで、この記事の上の画像のように Index ページ上で Bootstrap Modal 内に詳細を表示するようにしてみます。

Bootstrap については、Visual Studio 2022 のテンプレートで、ターゲットフレームワーク .NET 7.0 として作成した ASP.NET Core MVC アプリのプロジェクトに Bootstrap.js, Boorstrap.css v5.1.0 が含まれています。Bootstrap Modal を使うために必要なものもそれらの中に含まれているので何も追加する必要はありません。

レイアウトページ _Layout.cshtml にはプロジェクトの Bootstrap.js, Boorstrap.css を参照する link タグ、script タグが含まれていますので、スキャフォールディングの際 _Layout.cshtml を使用するように設定すれば、それらが参照されるようになります。

Bootstrap5 Modal の詳しい説明は Bootstrap のドキュメント「Modal (モーダル)」にあります。普通の html + css + javascript のページに Bootstrap5 Modal を組み込むなら、そのドキュメントから十分な情報が得られると思います。

ASP.NET Core MVC アプリに、Bootstrap5 Modal を組み込んで、Index ページにのアクションリンクをクリックして詳細データを取得し、Index ページ上で Modal に表示するにはどうしたらいいかというのががこの記事のポイントで、それを以下に述べます。

まずコントローラーのアクションメソッドですが、Index はチュートリアルのものと全く同じ、Details も最後の一行で部分ビューを返すように変更する以外はチュートリアルのものと同じです。

コードは以下の通りとなります。この記事ではアクションメソッドの名前を Index3, Details3 としています。

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MvcNet7App.Data;
using MvcNet7App.Models;

namespace MvcNet7App.Controllers
{
    public class StudentsController : Controller
    {
        private readonly SchoolContext _context;

        public StudentsController(SchoolContext context)
        {
            _context = context;
        }

        // Student のレコード一覧を取得しビューに渡す
        public async Task<IActionResult> Index3()
        {
            return _context.Students != null ?
                   View(await _context.Students.ToListAsync()) :
                   Problem("Entity set 'SchoolContext.Students'  is null.");
        }

        // 詳細を表示する部分ビュー用のアクションメソッド
        public async Task<IActionResult> Details3(int? id)
        {
            if (id == null || _context.Students == null)
            {
                return NotFound();
            }

            //var student = await _context.Students
            //    .FirstOrDefaultAsync(m => m.ID == id);
            var student = await _context.Students
                                        .Include(s => s.Enrollments)
                                            .ThenInclude(e => e.Course)
                                        .AsNoTracking()
                                        .FirstOrDefaultAsync(m => m.ID == id);

            if (student == null)
            {
                return NotFound();
            }

            // 部分ビューを返すように変更
            return PartialView(student);
        }
    }
}

次に、上の Index アクションメソッドに対応するビューですが、スキャフォールディングで自動生成されたコードに (1) Modal 部分を実装、(2) Details アクションリンクを JavaScript のメソッドを呼び出すよう変更、(3) fetch API でサーバーに要求を出し、応答として返される部分ビューを Modal 内の div 要素に書き込んだ後 Modal を表示する JavaScript のメソッドを追加します。

コードは以下の通りです。Modal 部分は Bootstrap 5 のドキュメント「Modal (モーダル)」の「Static backdrop」セクションのサンプルコードをコピペし、若干修正をして利用しています。詳細を書き込む div 要素に id="details" を追加したこと、デフォルトの "medium" サイズでは幅が足らないので CSS に modal-lg を追加したこと、Understood ボタンは削除したことが主な違いです。

@model IEnumerable<MvcNet7App.Models.Student>

@{
    ViewData["Title"] = "Index3";
}

<h1>Index3</h1>

<!-- (1) Modal 部分を実装 -->
<div class="modal fade"
     id="staticBackdrop"
     data-bs-backdrop="static"
     data-bs-keyboard="false" tabindex="-1"
     aria-labelledby="staticBackdropLabel"
     aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title"
                    id="staticBackdropLabel">
                    Student Details
                </h5>
                <button type="button"
                        class="btn-close"
                        data-bs-dismiss="modal"
                        aria-label="Close">
                </button>
            </div>
            <div class="modal-body" id="details">
                ...
            </div>
            <div class="modal-footer">
                <button type="button"
                        class="btn btn-primary"
                        data-bs-dismiss="modal">
                    Close
                </button>
            </div>
        </div>
    </div>
</div>

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.LastName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.FirstMidName)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.LastName)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.FirstMidName)
                </td>
                <td>
                    @* (2) クリックで JavaScript の showDetails
                    を呼び出す。引数には Student の ID を渡す *@ 
                    <a href="javascript:showDetails(@item.ID)">
                        Details
                    </a>
                </td>
            </tr>
        }
    </tbody>
</table>

@section Scripts {
    <script type="text/javascript">

        // (3) fetch API でサーバーに要求を出し、応答として返される
        // 部分ビューを Modal 内の div 要素に書き込んだ、後 Modal を
        // 表示する

        // Modal を表示するためのヘルパーメソッド
        const showBootstrapModal = () => {
            // staticBackdrop は Modal の div 要素の id
            let divModal = document.getElementById('staticBackdrop');
            let myModal = new bootstrap.Modal(divModal);
            myModal.show();
        }

        const showDetails = async (id) => {
            // 部分ビュー用アクションメソッドの url
            // id は Student テーブルのレコードの ID
            const url = "/Students/Details3/" + id;

            // Student 詳細を表示す��� Modal 内の div 要素
            const resultDiv = document.getElementById('details');

            const response = await fetch(url);
            if (response.ok) {
                // 部分ビューのテキストを取得
                const text = await response.text();

                // テキストを Modal 内の div 要素に書き込み
                resultDiv.innerHTML = text;

                // Modal を表示
                showBootstrapModal();
            }            
        }

    </script>
}

最後に、Details アクションメソッドに対応する部分ビューですが、以下の通りとなっています。チュートリアルで自動生成されたコードから部分ビューに不要な部分を削除しただけです。

@model MvcNet7App.Models.Student

<div>
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.LastName)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.LastName)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.FirstMidName)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.FirstMidName)
        </dd>
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.EnrollmentDate)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.EnrollmentDate)
        </dd>

        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Enrollments)
        </dt>
        <dd class="col-sm-10">
            <table class="table">
                <tr>
                    <th>Course Title</th>
                    <th>Grade</th>
                </tr>
                @foreach (var item in Model.Enrollments)
                {
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Course.Title)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Grade)
                        </td>
                    </tr>
                }
            </table>
        </dd>
    </dl>
</div>

Tags: , , ,

CORE

Blazor アプリで Bootstrap5 Modal の利用

by WebSurfer 2023年3月11日 14:09

Blazor アプリで Bootstrap5 の Modal を使う方法を書きます。この記事では Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor Web Assembly を例に使います。(Blazor Server でもほぼ同じようにしてできます)

Blazor アプリで Bootstrap Modal

Bootstrap5 Modal の詳しい説明は Bootstrap のドキュメント「Modal (モーダル)」にあります。普通の html + css + javascript のページに Bootstrap5 Modal を組み込むなら、そのドキュメントから十分な情報が得られると思います。

JavaScript のメソッドを呼び出すのがいろいろややこしい Blazor アプリに、Bootstrap5 Modal を組み込むにはどうしたらいいかというのががこの記事のポイントで、それを以下に述べます。

Visaul Studio 2022 のテンプレートで作った .NET 6.0 の Blazor アプリには bootstrap.min.css v5.1.0 が組み込み済みです。ただし、それだけでは Modal は使えません。使うには bootstrap.js が必要なので同じバージョンのものを wwwroot 下に追加します。

加えて、JavaScript で Modal を表示するためのコードを含んだ外部スクリプトファイルを作成します。内容は以下の通りです。Bootstrap のドキュメント「Via JavaScript」を参考にしました。ファイル名は exampleJsInterop.js としています (名前は任意)。

window.showBootstrapModal = () => {
    // staticBackdrop は modal 表示する div 要素の id
    let divModal = document.getElementById('staticBackdrop');
    let myModal = new bootstrap.Modal(divModal);
    myModal.show();
}

Modal を表示するには、Bootstrap のドキュメント「Via data attributes」に書かれているように、表示に必要な属性を付与した button のような要素を使う方法もあります。その方法で良ければ、上のスクリプトファイル exampleJsInterop.js は不要です。ただし、その場合でも bootstrap.js は必要ですので注意してください。

bootstrap.js ファイルと exampleJsInterop.js ファイルを wwwroot 下に配置し、wwwroot/index.html にそのファイルへの参照を追加します。下の画像の赤枠を見てください。青枠は既存の bootstrap.min.css のものです。

外部スクリプトファイルの追加

Bootstrap5 は jQuery に依存していないそうですので jquery.js は不要です。(上の画像では jquery.js も追加されていますが、Bootstrap5 とは関係ない別の目的です)

Blazor Sever の場合、外部スクリプトファイル bootstrap.js と exampleJsInterop.js への参照を追加するのは Pages/_Layout.cshtml になります。そこだけが Blazor Web Assembly と Blazor Server の違いです。

Pages フォルダ下に Razor コンポーネントを追加し、それに Bootstrap のドキュメント「Live demo」のコードをコピーします。それだけで[Launch static backdrop modal]ボタンをクリックすると Modal が表示されるようになります。

Blazor アプリで Bootstrap Modal

JavaScript で Modal を表示するには、外部スクリプトファイル exampleJsInterop.js の showBootstrapModal メソッドを呼び出してやります。それを含めた Razor コンポーネント全体のコードは以下のようになります。

[Via JavaScript]ボタンに設定した @onclick="ShowBootstrapModal" で @code 内の ShowBootstrapModal メソッドを呼び出し、その中の InvokeVoidAsync メソッドで showBootstrapModal メソッドを呼び出しています。

@page "/modal"
@inject IJSRuntime JSRuntime;

<PageTitle>Bootstrap Modal</PageTitle>

<!-- Modal -->
<div class="modal fade" 
    id="staticBackdrop" 
    data-bs-backdrop="static" 
    data-bs-keyboard="false" tabindex="-1" 
    aria-labelledby="staticBackdropLabel" 
    aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" 
                    id="staticBackdropLabel">
                    Modal title
                </h5>
                <button type="button" 
                    class="btn-close" 
                    data-bs-dismiss="modal" 
                    aria-label="Close">
                </button>
            </div>
            <div class="modal-body">
                ...
            </div>
            <div class="modal-footer">
                <button type="button" 
                    class="btn btn-secondary" 
                    data-bs-dismiss="modal">
                    Close
                </button>
                <button type="button" 
                    class="btn btn-primary">
                    Understood
                </button>
            </div>
        </div>
    </div>
</div>

<h1>Bootstrap Modal</h1>

<!-- Via JavaScript -->
<button type="button" class="btn btn-primary" 
    @onclick="ShowBootstrapModal">
    Via JavaScript
</button>

<br />
<br />

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" 
    data-bs-toggle="modal" 
    data-bs-target="#staticBackdrop">
    Launch static backdrop modal
</button>

@code {
    private async Task ShowBootstrapModal()
    {
        await JSRuntime
            .InvokeVoidAsync("showBootstrapModal");
    }
}

JavaScript のメソッドを呼び出す方法の詳細は Microsoft のドキュメント「ASP.NET Core Blazor で .NET メソッドから JavaScript 関数を呼び出す」に書かれていますので興味がありましたら読んでください。

Tags: , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar