【食事内容管理Webアプリ】FullCalendarによるカレンダー作成②

今回はカレンダー内に表示するメニューをサーバから設定し、動的に変更できるようにしていきます。

前回までのあらすじ&今回の目標

カレンダー作成①では、FullCalendarを使用してカレンダーを生成した後、食事のメニューを表示させるところまで実装しました。

しかしながら、メニューについてはJavaScriptに直書きとなっているため、この記事ではメニュー情報を外部から取得して設定することを目標に進めていきたいと思います!

データの取得&反映方針

まずデータ(メニュー情報)の取得方法についてですが、今回はSpring BootThymeleafを使って実現していきます。上記二つを選定した理由は筆者が使用しているフレームワークというだけで、ほかに特別な理由はありません。

データはデータベースに保管されているものと想定し、Spring Bootでデータベースにアクセスして取得したデータをThymeleafにてHTML、JavaScriptに反映する流れで実現していきます。

実際に実装してみた

Spring Bootのプロジェクトは以下の手順で実施しています。

  1. 「新規作成」から「Spring スターター・プロジェクト (Spring Initializr)」を選択
  2. 使用するJavaのバージョン等の設定を選択(その他の項目は任意の内容でよいです)
  3. プロジェクト依存関係にて必要な「Thymeleaf」を追加

次にControllerクラスを作成します。

本来はこんな書き方はしないと思いますが、全体像がわかりやすいようにControllerクラスに全処理を書いてみました。

またデータはデータベースから「key:物理名」、「value:値」のマップ変数のリストで取得することとしています。

ただデータベースへのアクセスはまだ先の話なので、
代わりに固定値を取得する関数「getMenu()」を用意しています。

最終的には取得したデータをリスト化し、”events“という名前でModelに格納しています。

Java (FoodAppController)
@Controller
@RequestMapping("/foodapp")
public class FoodAppController {

	@GetMapping("calendar")
	public String calendar(Model model) {
		// FullCalendarで表示するイベント(メニュー情報)を保持するリスト
		List<EventBean> events = new ArrayList<>();
		// TODO データベースからメニュー情報を取得する処理に置き換え予定
		List<Map<String, Object>> menu = getMenu();
		
		for (Map<String, Object> dish : menu) {
		  // イベントの内容を保持するBeanクラス
			EventBean event = new EventBean();
			
			event.setTitle((String)dish.get("dish_name"));
			event.setStart((String)dish.get("eating_date"));
			event.setBackgroundColor((String)dish.get("back_ground_color");
			events.add(event);
		}
		
		model.addAttribute("events", events);
		
		return "calendar";
	}
	
	private List<Map<String, Object>> getMenu() {
	  
		List<Map<String, Object>> menu = new ArrayList<>();
		Map<String, Object> dish= new HashMap<>();
		
		dish.put("dish_name", "牛丼");
		dish.put("eating_date", "2024-11-01");
		dish.put("back_ground_color", "blue");
		
		menu.add(dish);
		
		return menu;
	}
}

JavaScriptに渡すオブジェクトはイベントの内容を保持するBeanクラスのオブジェクトとしました。

Beanクラスには今回のカレンダー出力に必要なFullCalendarのプロパティのみ持たせています。

また@Dataでgetter/setterの記述を省略しています。

Java (EventBeanクラス)
@Data
public class EventBean {
	// 食べた日付
	private String start;
	// 食べた料理名
	private String title;
	// 朝食:red、昼食:orange、夕食:blue
	private String backgroundColor;
}

Beanクラスに不要なプロパティまで持たせてしまった場合、そのプロパティにnullを設定したオブジェクトをJavaScript側に渡してしまいます。

想定外の動作をしてしまう可能性があるため、不要であれば持たせないようにしましょう。

Java (EventBeanクラスに不要プロパティあり)
@Data
public class EventBean {
	// 食べた日付
	private String start;
	// 食べた料理名
	private String title;
	// 朝食:red、昼食:orange、夕食:blue
	private String backgroundColor;
	// URL(今回使用しないプロパティ)
	private String url;
}

○上記の場合にJavaScriptに渡すオブジェクト

この例の場合、urlプロパティが設定されているためイベントをクリックすると設定されたURLにアクセスしようとしますが、今回はnullが設定されているため下図のように意図しないURLにアクセスしようとして「404 not found」のエラーとなります。

○404 not found (エラーページは作成していないためWhitelabel Error Pageとなる)


JavaScriptにはFullCalendarでカレンダーを出力するコードを記載します。

前回から大きく変わっている点としては、イベントに直書きの配列ではなく、引数のオブジェクトを渡しているところ(4行目)です。

後はここにEventBeanクラスのオブジェクトを入れることができれば、イベントがカレンダー内に表示されます。

editcalendar.js
function initializeCalendar(events) {
	let calendarEl = document.getElementById('calendar');
	let calendar = new FullCalendar.Calendar(calendarEl, {
		events
	});
	calendar.render();
}

最後にhtmlです。

htmlは「id=’calendar’」をもつ要素を作成(9行目)し、DOM読み込み後にJavaScriptの処理が走る(11行目)ようにすればOKでしたね。

また今回はThymeleafの記述を追加しています。(2行目、6行目、10~11行目)

特に重要なのは11行目で、Controllerクラスで”events“と命名したイベントのオブジェクトをThymeleafのインライン処理にてJavaScript側に渡しています。

calendar.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ja">
  <head>
    <meta charset='utf-8' />
    <script src='https://cdn.jsdelivr.net/npm/fullcalendar@6.1.14/index.global.min.js'></script>
    <script th:src="@{/js/editcalendar.js}"></script>
  </head>
  <body>
    <div id='calendar'></div>
	<script type="text/javascript" th:inline="javascript">
		document.addEventListener('DOMContentLoaded', initializeCalendar(/*[[${events}]]*/ null));
	</script>
  </body>
</html>

Thymeleafについては下記の記事で、詳しく説明していますのでそちらをご確認ください。


上記によって出力されるページは次のようになります。

○出力結果

JavaScript側にメニュー内容を直接書かずにメニューを表示させることができました!

ただ画面にカレンダーが入り切っていないため、もうひと踏ん張りします。

JavaScriptのコードにFullCalendarのプロパティを追加(4行目)しました。これによって画面にカレンダー全体が入るようになりましたね!

editcalendar.js
function initializeCalendar(events) {
	let calendarEl = document.getElementById('calendar');
	let calendar = new FullCalendar.Calendar(calendarEl, {
	  contentHeight: "auto",
		events
	});
	calendar.render();
}

○出力結果

今後の予定

今回はSpring BootとThymeleafを用いて、外部からのデータでFullCalendarのイベントを追加しました。次回はデータを実際にデータベースから取得し画面に出力できるように改良していきます。

今日の夕飯は「カルボナーラ」でした。それではまた。。

コメント

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