【Flask】TODOアプリ作成その7:モーダルダイアログ表示の実装

概要

Pythonのflaskフレームワークを使用して、TODOリストを管理するWEBアプリを作成したのでまとめた。
flaskのGET/POSTの方法やセッション等の扱い、Jinjaテンプレートの使い方について、当アプリを作成しながら振り返ることが目的。

今回はJavaScriptを使用してモーダルダイアログを表示する機能を追加した。
尚、実装はJavaScriptのライブラリであるjQueryを使用している。

 

前提

flaskフレームワークを使用して作成したTODOアプリに対して改修を行う。

あわせて読みたい

概要 Pythonのflaskフレームワークを使用して、TODOリストを管理するWEBアプリを作成したのでまとめた。 flaskのGET/POSTの方法やセッション等の扱い、Jinjaテンプレートの使い方について、当アプリを作成しながら[…]

 

機能説明

モーダルダイアログ表示機能

・ログアウトボタン押下時、JavaScriptを使用して確認ダイアログを表示する
・削除ボタン押下時、JavaScriptを使用して確認ダイアログを表示する
・確認ダイアログにて「はい」を押下すると、処理を続行する
・確認ダイアログにて「いいえ」または×ボタンを押下すると、処理を中断する

対象画面

・TODOトップ画面
・TODO詳細画面

 

ダイアログ表示機能

画面状態

◆TODOトップ画面

▲ログアウトボタンを押下する

 

▲確認ダイアログを表示する

 

▲確認ダイアログに「はい」を押下するとログアウト、「いいえ」を押下するとダイアログを閉じる

 

◆TODO詳細画面

▲削除するボタンを押下する

 

▲確認ダイアログを表示する

 

▲確認ダイアログに「はい」を押下すると削除実行、「いいえ」を押下するとダイアログを閉じる

 

ファイル構成

以下の赤文字箇所について、追加修正等を行う。

 

ログアウトダイアログ表示機能解説

画面側

confirm_modal.html

 


<div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="confirmModalTitle"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p id="confirmModalContent"></p>
      </div>
      <div class="modal-footer">
        <button type="button" id="confirmModalYes" class="btn btn-primary">はい</button>
        <button type="button" class="btn btn-secondary modal-close" data-bs-dismiss="modal">いいえ</button>
      </div>
    </div>
  </div>
</div>

ダイアログのひな型となるモーダル部品。
htmlを分離することで、他画面からインクルードしてモーダル部品を参照できる。

top.html

 


<!-- モーダルエリア -->
{% include 'components/confirm_modal.html' %}

{% endblock %}

{% block extra_js %}
<script src="{{ url_for('static', filename='js/top.js') }}"></script>
{% endblock %}

モーダル画面を使用するため、ダイアログ部品を以下のようにインクルードする。

{% include 'components/confirm_modal.html' %}

 

また、モーダルダイアログ表示イベントを定義したtop.jsを参照する。

<script src="{{ url_for('static', filename='js/top.js') }}"></script>

 

JS側

top.js

/**
 * ログアウトボタン押下時
 */
$(document).on("click", "#logout", function(e) {
    e.preventDefault();

    // モーダル情報セット
    $("#confirmModalTitle").text("確認");
    $("#confirmModalContent").text("ログアウトしてもよろしいですか?");

    // モーダルの「はい」押下イベントを定義
    $("#confirmModalYes").on("click", function(e){
        window.location.href = $("#logout").attr("href");
    });

    // モーダル表示
    let modal = new bootstrap.Modal($("#confirmModal"));
    modal.show();
});

ログアウトボタン押下時のイベントを定義。

モーダルのタイトルとメッセージを設定し、ダイアログの「はい」押下時のイベントを動的に定義して、モーダルウィンドを表示する。

※削除確認ダイアログの機能も同じつくりのため、説明は割愛する。

 

ファイル詳細

confirm_modal.html

<div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="confirmModalTitle"></h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <p id="confirmModalContent"></p>
      </div>
      <div class="modal-footer">
        <button type="button" id="confirmModalYes" class="btn btn-primary">はい</button>
        <button type="button" class="btn btn-secondary modal-close" data-bs-dismiss="modal">いいえ</button>
      </div>
    </div>
  </div>
</div>

 

top.html

{% extends "base.html" %}
{% block title %}TODOトップ{% endblock %}

{% block main %}
<div class="container mt-5">
  <h2 class="text-center">{{ session["name"] }} さんのタスク一覧</h2>
  <a href="{{ url_for('show_create') }}" class="btn btn-primary me-3">タスク登録</a>
  <a href="{{ url_for('logout') }}" id="logout" class="btn btn-primary">ログアウト</a>
  <div class="card mt-4">
    <div class="card-body">
      {% for msg in errors %}
      <div id="error-message" class="text-danger mb-3">{{ msg }}</div>
      {% endfor %}
      <table class="table table-striped">
        <thead>
          <tr>
            <th>カテゴリ</th>
            <th>タイトル</th>
            <th>タスク名</th>
            <th>期日</th>
            <th>ステータス</th>
            <th>アクション</th>
          </tr>
        </thead>
        <tbody>
          {% for todo_item in todos %}
          <tr>
            <td>{{ todo_item["category"] }}</td>
            <td>{{ todo_item["title"] }}</td>
            <td><a href="{{ url_for('show_detail', t_id=todo_item['id']) }}">{{ todo_item["content"] }}</a></td>
            <td>{{ todo_item["due_date"] }}</td>
            <td>{{ todo_item["status"] }}</td>
            <td><a href="{{ url_for('update_todo_done', t_id=todo_item['id']) }}" class="btn btn-success">完了</a></td>
          </tr>
          {% endfor %}
        </tbody>
      </table>
    </div>
  </div>
</div>

<!-- モーダルエリア -->
{% include 'components/confirm_modal.html' %}

{% endblock %}

{% block extra_js %}
<script src="{{ url_for('static', filename='js/top.js') }}"></script>
{% endblock %}

 

detail.html

{% extends "base.html" %}
{% block title %}TODO詳細{% endblock %}

{% block main %}
<div class="container mt-2">
  <a href="{{ url_for('top') }}" class="btn btn-primary mb-3">戻る</a>
  <h2 class="text-center">TODO詳細</h2>
  <div class="card mt-4 border">
    <div class="card-body">
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>カテゴリ:</h5>
        </div>
        <div class="col-sm-9">
          <p>{{ todo["category"] }}</p>
        </div>
      </div>
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>タイトル:</h5>
        </div>
        <div class="col-sm-9">
          <p>{{ todo["title"] }}</p>
        </div>
      </div>
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>タスク内容:</h5>
        </div>
        <div class="col-sm-9">
          <p>{{ todo["content"] }}</p>
        </div>
      </div>
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>ステータス:</h5>
        </div>
        <div class="col-sm-9">
          <p>{{ todo["status"] }}</p>
        </div>
      </div>
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>メモ:</h5>
        </div>
        <div class="col-sm-9">
          {% if todo["memo"] %}
          <p>{{ todo["memo"].replace("\r\n", "<br>") | safe }}</p>
          {% else %}
          <p></p>
          {% endif %}
        </div>
      </div>
      <div class="row border p-2 mb-2">
        <div class="col-sm-3">
          <h5>期日:</h5>
        </div>
        <div class="col-sm-9">
          <p>{{ todo["due_date"] }}</p>
        </div>
      </div>
      <div class="d-flex justify-content-center mt-2">
        <a href="{{ url_for('show_edit', t_id=todo['id']) }}" class="btn btn-primary mb-3 me-3">編集する</a>
        <a href="{{ url_for('delete_todo', t_id=todo['id']) }}" id="deleteTask" class="btn btn-danger mb-3">削除する</a>
      </div>
    </div>
  </div>
</div>

<!-- モーダルエリア -->
{% include 'components/confirm_modal.html' %}

{% endblock %}

{% block extra_js %}
<script src="{{ url_for('static', filename='js/detail.js') }}"></script>
{% endblock %}

 

top.js

"use strict";

/**
 * ログアウトボタン押下時
 */
$(document).on("click", "#logout", function(e) {
    e.preventDefault();

    // モーダル情報セット
    $("#confirmModalTitle").text("確認");
    $("#confirmModalContent").text("ログアウトしてもよろしいですか?");

    // モーダルの「はい」押下イベントを定義
    $("#confirmModalYes").on("click", function(e){
        window.location.href = $("#logout").attr("href");
    });

    // モーダル表示
    let modal = new bootstrap.Modal($("#confirmModal"));
    modal.show();
});

 

detail.js

"use strict";

/**
 * 削除ボタン押下時
 */
$(document).on("click", "#deleteTask", function(e) {
    e.preventDefault();

    // モーダル情報セット
    $("#confirmModalTitle").text("タスクの削除");
    $("#confirmModalContent").text("タスクを削除します。よろしいですか?");

    // モーダルの「はい」押下イベントを定義
    $("#confirmModalYes").on("click", function(e){
        window.location.href = $("#deleteTask").attr("href");
    });

    // モーダル表示
    let modal = new bootstrap.Modal($("#confirmModal"));
    modal.show();
});

 

 

スポンサーリンク