前回はスマホ表示時の切り替えタブを実装しました。
↓前回の記事はこちら
今回はカレンダーやデータ検索のinputが変更されたら、検索を押さなくても処理が実行されるように修正します。
カレンダーの月選択部分の修正
まずはカレンダー上部の月選択の修正を行います。
現状は「<」「>」で月操作をしますが、離れた月を閲覧したい際に何回もクリックするのは不便なので、「2022年11月」のタイトル部分をinput要素に変更して、タイトル部分からも付き選択ができるようにします。
HTML・CSS修正
HTMLの構造を以下のように修正します。
<!--書き換え前 338行目付近-->
<p>
<a id="js-prevMonth" href="<?php echo $calendar_link_prev; ?>"><</a>
<?php echo $calendar_title; ?>
<a id="js-nextMonth" href="<?php echo $calendar_link_next; ?>">></a>
<a id="js-nowMonth" href="<?php echo $calendar_link_now; ?>">今月</a>
</p>
<!--修正後-->
<div class="p-monthsearch"> <!--pタグからdivタグに修正-->
<a href="<?php echo $calendar_link_prev; ?>"><</a>
<!--以下をinputタグに修正-->
<input type="month" id="calendarMonth" value="<?php echo $calendar_title; ?>">
<a href="<?php echo $calendar_link_next; ?>">></a>
<a href="<?php echo $calendar_link_now; ?>">今月</a>
</div><!--divに修正-->
HTML構造を変更したのでスタイルが崩れてしまいます。
このパーツはこのあとのデータ一覧検索でも使い回すので、専用のスタイリングを指定します。
まずはcssディレクトリ内「project」直下に _monthsearch.scss というファイルを作成し以下を記述します。
@use "../global" as g;
@use "../foundation/mixin" as m;
.p-monthsearch {
font-size: 1.8rem;
display: flex;
align-items: center;
@include m.mq(tab){
justify-content: center;
}
&.center{
justify-content: center;
padding: 3rem 0 1rem;
@include m.mq(tab){
padding: 0 0 1rem;
}
}
@include m.mq(tab) {
font-size: 2.2rem;
text-align: center;
}
a {
display: inline-block;
padding: 0 1rem;
font-size: 1.7rem;
font-weight: bold;
&:last-of-type {
font-weight: normal;
margin-left: 1rem;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: #ddd;
}
}
input[type="month"] {
position: relative;
margin: 0 0.5rem;
padding: 0.3rem 1rem;
font-size: 1.8rem;
max-width: 12rem;
text-align: center;
cursor: pointer;
&::-webkit-calendar-picker-indicator {
position: absolute;
cursor: pointer;
width: 100%;
height: 100%;
opacity: 0;
}
}
}
続いて同じく「project」直下にある _index.scss の一番下に以下を追記します。
@use "monthsearch"
上記を記述したら、cssディレクトリ直下の style.scss を保存します。
スタイリングの指定ができると以下のような見た目になります。
日付タイトル修正
タイトル部分が「Y年n月」指定になってるので以上のような表示になっています。
この部分を修正します。
//321行目付近
$calendar_title = date('Y-m', $base_date);
第一引数を「Y年n月」から「Y-m」に修正しました。
月選択変更と同時に処理開始
先程追加したinput要素で、日付を変更したら検索を押下しなくても処理が実行されるようにします。
実装方法はinput要素に「onchange」属性を追加し、値が変更されたらJavaScriptイベントを発火させる方法です。
まずは関数を作成します。このあと実装するデータ検索でも同じ処理を使うので、引数を用いてどちらでも使用できる柔軟な関数を作成します。
const onChangeMonth = (param,button) => {
const monthInput = document.getElementById(button); //引数で指定したボタンを取得
const url = new URL(window.location.href); //現在のURLを取得
if (url.searchParams.has('page_id')) {
url.searchParams.delete('page_id'); //もしページ番号パラメータがある場合は削除
}
url.searchParams.set(param, monthInput.value); //引数で指定したパラメータにinputの値をセット
history.pushState('', '', url); //現在のURLを書き換え
location.reload(); //画面更新
}
途中if文で「page_id」がある場合はそのパラメータを削除するプログラムを挟んでいますが、これはデータの2ページ目以降を閲覧中に月を変更した際、変更先の月に10件以上データがないと、「データがありません」+ページネーション非表示という現象が発生します。
つまりURLを直接変更しないと、正しいデータ一覧を見ることができなくなってしまうということです。このような処理を防ぐために、if文の処理を挟みます。
それではこの関数を月選択のinputにセットします。
<!--340行目付近-->
<input type="month" id="calendarMonth" value="<?php echo $calendar_title; ?>" onchange="onChangeMonth('ym', 'calendarMonth');">
検索ボタンはありませんが、月を選択しただけで検索されたかのように処理が実行されるようになりました。
データ検索の日付検索部分の修正
続いて収支データの日付検索部分を修正します。
現在は日付範囲指定にしていますが、これをカレンダー同様月ごとの検索に変更します。
HTML修正
まずはカレンダーのときと同様にHTMLを修正します。
<!--書き換え前 483行目付近-->
<form class="p-form p-form--center p-form--date-search" action="" method="POST">
<input type="hidden" name="search">
<label for="date-search">
<input type="date" id="dateFrom" name="date_from" value="<?php echo $searchDateFrom; ?>">
〜
<input type="date" id="dateTo" name="date_to" value="<?php echo $searchDateTo; ?>">
</label>
<input class="c-button c-button--bg-gray c-button--search" type="submit" name="date-search" value="検索">
<input class="c-button c-button--bg-gray" type="submit" name="all-search" value="全データ表示">
</form>
<!--修正後-->
<div class="p-monthsearch center">
<a href=""><</a>
<input type="month" id="searchMonth" value="" onchange="">
<a href="">></a>
<a href="">今月</a>
</div>
CSSは先程カレンダー部分の修正の際に指定したので、以上を修正するだけで以下のような見た目になります。
データ検索処理の修正
これまでのデータ検索処理を書いていた部分を削除orコメントアウトします。
//削除部分 25行目付近
//日付データ検索
if (isset($_POST['search']) && isset($_POST['date-search'])) :
//検索が押されたときの処理
$date_from = filter_input(INPUT_POST, 'date_from', FILTER_SANITIZE_SPECIAL_CHARS);
$date_to = filter_input(INPUT_POST, 'date_to', FILTER_SANITIZE_SPECIAL_CHARS);
$_SESSION['searchDateFrom'] = $date_from;
$_SESSION['searchDateTo'] = $date_to;
elseif (isset($_POST['search']) && isset($_POST['all-search'])) :
//全表示検索時
$_SESSION['searchDateFrom'] = '';
$_SESSION['searchDateTo'] = date('Y-m-d');;
else :
$searchDateFrom = date('Y-m-01');
$searchDateTo = date('Y-m-d');
endif;
//日付指定セッション処理
if (isset($_SESSION['searchDateFrom']) && isset($_SESSION['searchDateTo'])) :
$searchDateFrom = $_SESSION['searchDateFrom'];
$searchDateTo = $_SESSION['searchDateTo'];
else :
$searchDateFrom = date('Y-m-01');
$searchDateTo = date('Y-m-d');
endif;
これまではPOST送信をして処理していましたが、修正後はGET送信で処理するので以上の削除部分に以下を追記します。
if (isset($_GET['search_month'])) :
$search_month = $_GET['search_month'];
else :
$search_month = date('Y-m');
endif;
この処理で現在どの月のデータを表示しているのかを取得しておきます。
続いて日付検索から月検索に変更したので、データを抽出しているSQLのWHEREの一部やbind_paramを修正する必要があります。
ファイル内検索で「date <=」や「$searchDateFrom」とすると変更する箇所が簡単に探すことができます。
//データ出力部分(PC) 521行目付近
$add_limit = 'LIMIT ?, ?'; //★追加
//records.date >=? AND records.date <=? から records.date LIKE ? に修正
//LIMIT以降削除(半角スペースは残す)
$sql_output = '
:
省略
:
WHERE records.date LIKE ? AND records.user_id=?
ORDER BY date DESC, input_time DESC ';
$stmt_dataoutput = $db->prepare($sql_dataoutput . $add_limit); //文字列連結で$add_limitを追加
$month_param = $search_month . '%'; //セットするパラメータを生成
$stmt_dataoutput->bind_param('siii', $month_param, $user_id, $page_param, $max_view); //セットする値を変更
//合計金額計算部分 618行目付近 date LIKE ?に変更
$sql = 'SELECT (SELECT SUM(amount) FROM records WHERE type=1 AND user_id = ? AND date LIKE ?) AS income, (SELECT SUM(amount) FROM records WHERE type=0 AND user_id = ? AND date LIKE ?) AS spending FROM records WHERE user_id = ? AND date LIKE ? LIMIT 1';
//620行目付近 bind_param変更
$stmt->bind_param('isisis', $user_id, $month_param, $user_id, $month_param, $user_id, $month_param);
//エクセル出力テーブル部分 669行目付近
$sql = '・・・省略・・・'; //削除
$stmt = $db->prepare($sql_dataoutput); //$sqlから$sql_dataoutputに変更
$stmt->bind_param('si', $month_param, $user_id); //bind_param変更
//PCページネーション部分 731行目付近
//records.date LIKE ?に変更
$sql = 'SELECT count(*) FROM records WHERE records.date LIKE ? AND records.user_id = ?';
$stmt->bind_param('si', $month_param, $user_id); //bind_param変更
//スマホデータ出力部分 770行目付近 bind_param変更
$stmt_dataoutput = $db->prepare($sql_dataoutput . $add_limit); //文字列連結で$add_limit追加
$stmt_dataoutput->bind_param('siii', $month_param, $user_id, $page_param, $max_view);
ファイル内検索で「date <=」や「$searchDateFrom」を検索した際に検索結果が0になったら修正完了です。
月選択部分の実装
この月選択部分をカレンダー上部の箇所と同様に動かせるように実装します。
まずはinputのvalueに表示中の月を設定します。
<input type="month" id="searchMonth" value="<?php echo $search_month;?>" onchange="">
そしてonchangeに関数をセットします。
<input type="month" id="searchMonth" value="<?php echo $search_month;?>" onchange="onChangeMonth('search_month', 'searchMonth');">
以上でinputで月変更部分を動かせるようになりました。
続いて「<」「>」「今月」のリンクを設定していきます。
カレンダーの部分では、その他のパラメータのことも考慮して条件分岐でリンクを生成しましたが、考慮するパラメータが多くなったので、セッションに保存する形に修正します。
まずパラメータを処理しているプログラムにセッション保存プログラムを追加します。
//月データ検索パラメータ処理
if (isset($_GET['search_month'])) :
$search_month = $_GET['search_month'];
$_SESSION['search_month'] = $search_month; //追加
else :
$search_month = date('Y-m');
endif;
//カレンダーパラメータ処理 ★移動させる★
if (isset($_GET['ym'])) :
$ym = $_GET['ym'];
$_SESSION['ym'] = $ym; //追加
else :
$ym = date('Y-m');
endif;
続いてセッションを処理するプログラムを上記の下に追記します。
//月データ検索セッション処理
if (isset($_SESSION['search_month'])) :
$search_month = $_SESSION['search_month'];
endif;
//カレンダーセッション処理
if (isset($_SESSION['ym'])) :
$ym = $_SESSION['ym'];
endif;
以上でパラメータとして渡っていなくても、セッションに保存されている値で表示していた月を保持することができます。
ただデータ一覧の表示中のページパラメータはセッションにすると少し複雑になるので、このまま進めます。
続いて「<」「>」「今月」のリンク生成プログラムを実装します。
データ検索のリンクはパラメータを考慮しなくて良いので、カレンダーの部分のように条件分岐をする必要はありません。
以下を月検索の要素のすぐ上に記述します。
<!--追記ここから 479行目付近-->
<?php
$base_date = strtotime($search_month); //パラメータもしくは現在の年月のタイムスタンプ
$prev = date('Y-m', strtotime('-1 month', $base_date)); //前月取得
$next = date('Y-m', strtotime('+1 month', $base_date)); //次月取得
$search_link_prev = '?search_month=' . $prev . '#all-data';
$search_link_next = '?search_month=' . $next . '#all-data';
$search_link_now = '?search_month=' . date('Y-m') . '#all-data';
?>
<!--追記ここまで-->
<div class="p-monthsearch center">
そして生成したリンクを設定します。
<div class="p-monthsearch center">
<a href="<?php echo $search_link_prev; ?>"><</a>
<input type="month" id="searchMonth" value="<?php echo $search_month; ?>" onchange="onChangeMonth('search_month', 'searchMonth');">
<a href="<?php echo $search_link_next; ?>">></a>
<a href="<?php echo $search_link_now; ?>">今月</a>
</div>
生成したリンクにアンカーリンクをつけました。これは月変更をするとページが再読込され上部に戻ってしまうので、再読込されたあともデータ一覧がすぐに表示されるようにします。
画面表示用のtableにidを付与します。
<!--501行目付近-->
<table class="p-table p-table--record-output" id="all-data">
カレンダーセルのリンク生成条件にsearch_monthを追加
カレンダーでデータがあるときにリンクを<td>の中に出力しているのですが、このリンクを生成するプログラムで、パラメータが存在するときは「&」つなぎにしている条件に今回追加した「search_month」パラメータも追加します
//詳細表示のリンク生成
if (isset($_GET['ym']) || isset($_GET['page_id']) || isset($_GET['search_month'])) : //条件追加
$detail_url = $_SERVER['REQUEST_URI'] . '&detail=' . $date;
else :
$detail_url = $_SERVER['REQUEST_URI'] . '?detail=' . $date;
endif;
以上でPCにおいては、月変更を検索ボタン無しでデータ出力を行う機能の実装は完了です。
スマホ表示はonchange属性をonblur属性に切り替える
しかしスマホでは以下のように変更し、指を離した瞬間に、再読み込みが行われてしまうので「完了」が押されたら処理を開始するように修正します。
現在はonclick属性にイベントを設定していますが、完了を押したら処理を始めるためには「onblur」属性に切り替える必要があります。(関数自体はそのまま)
PCのときは「onclick属性」にスマホのときは「onblur属性」になるようにします。
以下をindex.phpの<scripit>〜</script>に追記します。
//onchange onblur切り替え
window.onload = function toggleChangeToBlur() { //画面が読み込まれたら以下の関数を実行
const calendarMonth = document.getElementById('calendarMonth'); //カレンダー上部のtype=monthを取得
const searchMonth = document.getElementById('searchMonth'); //データ一覧上部のtype=month取得
if (window.outerWidth < 900) { //もし画面幅が900px未満であれば
//両月選択inputからonchange属性を削除
calendarMonth.removeAttribute('onchange');
searchMonth.removeAttribute('onchange');
//両月選択inputにonblur属性とイベントを追加
calendarMonth.setAttribute('onblur', 'onChangeMonth("ym", "calendarMonth");');
searchMonth.setAttribute('onblur', 'onChangeMonth("search_month", "searchMonth");');
}
}
画面幅で条件分岐をし、trueのとき(スマホ表示のとき)に属性の切り替えを行います。
以上のプログラムを追記することで、スマホで見る際は完了を押してから処理が走るようになります。
最後に
今回はカレンダーとデータ一覧に設置している月や日付選択部分を、検索を押さなくても処理を始めるように修正しました。
次回はカレンダーセルクリックから、その日のデータを追加できるようにします。
最後までお読みいただきありがとうございました。
コメント