無理しないでゆっくり休んでね!

Todoリスト作成日記

JavaScriptとPHPを使って、自分用のTodoリストを作ります。

HTML構造

HTMLはとりあえずこんな感じです。

追加用のinputタスクを表示するところです。

 <main>
        <section id="todo-input-section">
            <h2>新しいタスクを追加</h2>
            <input type="text" id="todo-input" placeholder="入力してください">
            <button id="add-todo-btn">追加</button>
        </section>

        <section id="todo-list-section">
            <h2>未完了のタスク</h2>
            <ul id="todo-list">
                <!-- ここにタスクが追加されます -->
            </ul>
        </section>

        <section id="completed-tasks-section">
            <h2>完了したタスク</h2>
            <ul id="completed-tasks">
                <!-- ここに完了したタスクが表示されます -->
            </ul>
        </section>
    </main>

新しいタスクを追加

未完了のタスク

完了したタスク

HTMLの修正とJavaScript

時間の記録が必須ですね。

spanタグを使って一行内に表示されるようにしましょう。

また、未完了のタスクを完了にするボタンもいります。

マークでもいいし、テキストでもいいし、ボタンを追加しました。

<section id="todo-input-section">
    <h2>新しいタスクを追加</h2>
    <input type="text" id="todo-input" placeholder="入力してください">
    <input type="hidden" id="task-created-time">
<button id="add-todo-btn"><i class="fas fa-plus"></i> 追加</button>
</section>

<section id="todo-list-section">
    <h2>未完了のタスク</h2>
    <ul id="todo-list">
        <!-- タスク例:
        <li>
            <span class="task-text">タスク内容</span>
            <span class="task-time">追加時間: 2023-10-31 12:30</span>
            <button class="complete-btn">完了</button>
        </li>
        -->
    </ul>
</section>

<section id="completed-tasks-section">
    <h2>完了したタスク</h2>
    <ul id="completed-tasks">
        <!-- タスク例:
        <li>
            <span class="task-text">タスク内容</span>
            <span class="task-time">追加時間: 2023-10-31 12:30</span>
            <span class="completion-time">完了時間: 2023-10-31 13:00</span>
        </li>
        -->
    </ul>
</section>
document.addEventListener('DOMContentLoaded', function() {
    // DOM要素の取得
    const taskInput = document.getElementById("todo-input"); // タスク入力フィールド
    const addButton = document.getElementById("add-todo-btn"); // タスク追加ボタン
    const pendingTasksList = document.getElementById("todo-list"); // 未完了タスクリスト
    const completedTasksList = document.getElementById("completed-tasks"); // 完了タスクリスト

    // タスク追加ボタンのクリックイベントリスナー
    addButton.addEventListener("click", function() {
        // 入力値を取得してトリム
        const description = taskInput.value.trim();

        if (description) {
            // タスクを追加し、入力フィールドをクリア
            addTask(description);
            taskInput.value = '';
        }
    });

    // すべてのタスクを取得する関数を呼び出す
    getAllTasks();

    // タスクを追加する関数
    function addTask(description) {
        fetch('addTask.php', {
            method: 'POST',
            body: new URLSearchParams({
                'description': description
            }),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                // タスクを追加した後、すべてのタスクを再度取得
                getAllTasks();
            } else {
                console.error(data.message);
            }
        });
    }

    // タスクを完了させる関数
    function completeTask(taskId) {
        fetch('completeTask.php', {
            method: 'POST',
            body: new URLSearchParams({
                'id': taskId
            }),
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        })
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                // タスクを完了した後、すべてのタスクを再度取得
                getAllTasks();
            } else {
                console.error(data.message);
            }
        });
    }

    // すべてのタスクを取得する関数
    function getAllTasks() {
        fetch('getTasks.php')
        .then(response => response.json())
        .then(data => {
            if (data.status === 'success') {
                // タスクを取得した後、タスクを表示する関数を呼び出す
                renderTasks(data.tasks);
            } else {
                console.error(data.message);
            }
        });
    }

    // タスクを表示する関数
    function renderTasks(tasks) {
        // タスクリストをクリア
        pendingTasksList.innerHTML = '';
        completedTasksList.innerHTML = '';

        // タスクごとに処理
        tasks.forEach(task => {
            const taskItem = document.createElement('li');
            taskItem.textContent = task.description + " (追加時間: " + task.added_time + ")";
            
            if(task.status === "completed") {
                taskItem.textContent += " (完了時間: " + task.completed_time + ")";
                completedTasksList.appendChild(taskItem);
            } else {
                const completeButton = document.createElement('button');
                completeButton.textContent = "完了";
                completeButton.addEventListener('click', () => completeTask(task.id));
                taskItem.appendChild(completeButton);
                pendingTasksList.appendChild(taskItem);
            }
        });
    }
});

PHP

データベース

まず、MySQLでデータベースを作成します!

字段名データ型説明
idINT, AUTO_INCREMENTタスクのID
descriptionVARCHAR(255)タスクの内容
added_timeDATETIMEタスクがリストに追加された時間
completed_timeDATETIME, NULLABLEタスクが完了した時間 (タスクが未完了の場合はNULL)
statusENUM(‘pending’, ‘completed’)現在のタスクの状態
tasks

SQL文は以下の通りです。

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    description VARCHAR(255) NOT NULL,
    added_time DATETIME NOT NULL,
    completed_time DATETIME,
    status ENUM('pending', 'completed') NOT NULL DEFAULT 'pending'
);

必要に応じて、さらに拡張や調整を行うこともできます。

たとえば、タスクの優先度を示すための「priority」フィールドを追加したり、タスクの締め切り日を示す「due_date」フィールドを追加するなどが考えられます。

ENUM データ型を使って、カテゴリーを定義する場合

タブ分類を行うつもりでしたが、少し面倒だったので、このままでやめておきます。

予め定義されたカテゴリーを使う場合、ENUM データ型を使って、カテゴリーをtasksテーブルに直接組み込むことができます。

ENUM データ型は、列(フィールド)が取り得る値を事前に定義したリストから選択する必要がある場合に使われるデータ型です。SQLデータベースで使用される型の一つで、指定されたリスト内の文字列のいずれか一つの値しか持つことができません。

以下は、ENUM型を使用してcategoryフィールドをtasksテーブルに追加する例です。

CREATE TABLE tasks (
    id INT AUTO_INCREMENT PRIMARY KEY,
    description VARCHAR(255) NOT NULL,
    added_time DATETIME NOT NULL,
    completed_time DATETIME,
    status ENUM('pending', 'completed') NOT NULL DEFAULT 'pending',
    category ENUM('仕事', '学習', '生活', '娯楽') NOT NULL
);

このテーブル定義では、新たにcategory列を追加しており、それは仕事学習生活娯楽の4つの値しか取ることができません。そして、タスクが作成される際には、これらのカテゴリーのいずれかが必ず指定されるようになっています。

db.php

データベース接続にするファイルを作成します。

<?php
$host = "データベースホスト名";
$dbname = "データベース名";
$user = "ユーザー名";
$pass = "パスワード";

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}
?>

addTask.php

a. タスクを追加する (addTask.php)

<?php
include 'db.php';

$description = $_POST['description'];
$added_time = date("Y-m-d H:i:s");

$stmt = $pdo->prepare("INSERT INTO tasks (description, added_time, status) VALUES (?, ?, 'pending')");
$stmt->execute([$description, $added_time]);

echo json_encode(['status' => 'success', 'message' => 'Task added successfully']);
?>

completeTask.php

b. タスクを完成済みにする (completeTask.php)

<?php
include 'db.php';

$taskId = $_POST['id'];
$completed_time = date("Y-m-d H:i:s");

$stmt = $pdo->prepare("UPDATE tasks SET status = 'completed', completed_time = ? WHERE id = ?");
$stmt->execute([$completed_time, $taskId]);

echo json_encode(['status' => 'success', 'message' => 'Task marked as completed']);
?>

getTasks.php

c. タスクを取得する (getTasks.php)

<?php
include 'db.php';

$stmt = $pdo->query("SELECT * FROM tasks");
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);

echo json_encode(['status' => 'success', 'tasks' => $tasks]);
?>

CSSスタイル

最後はCSSファイルを書きます。

HTMLの部分は非常にシンプルなので、タグにスタイルを適用するだけで完成です。

新しいタスクを追加

未完了のタスク

  • タスク内容 追加時間: 2023-10-31 12:30

完了したタスク

  • タスク内容 追加時間: 2023-10-31 12:30 完了時間: 2023-10-31 13:00

まとめ

これは僕が作った最終版です。

PC

モバイル

コメント

タイトルとURLをコピーしました