Ajax:プルダウンリストの内容を画面遷移なしに更新する STS +Spring Boot+thymeleaf
Ajaxを使って、画面遷移せずに、画面の一部を更新する「非同期処理」をやります。
STS3(3.9.6)+SpringBoot2.0+Tymeleaf3.0迄は動作確認しています。
jQueryを使う
jQueryの$Ajaxの仕組みを使うと、比較的容易に処理は書けます。
ですが、SpringBoot+thymeleafの機能を使っているHTMLの一部を書き換えるのは、JSPとは違った一手間が必要になります。
今回は、都道府県の選択にあわせて、適切な市区町村のリストに更新するようなパターンをイメージしてサンプルを作ります。
まず、動作イメージです。
こういう2段のプルダウンを用意します。
そして、上のプルダウンの選択で、画面遷移なく下のプルダウンに選択肢を表示させます。
実現するためのHTMLとその仕組
HTMLファイルの名前が結構重要になので、名前を決めておきます。
今回は、hello3.htmlにします。
hello3.html
<form role="form" id="hello3Form" action="/outpg01" th:action="@{/outpg01}" th:object="${hello3Form}" method="post">
<select id="singleSelect" name="selectedItem">
<option value="">---</option>
<option th:each="item : ${selectItems}" th:value="${item.value}" th:text="${item.value}" th:selected="${item.value} == *{selectedItem}">singleSelect</option>
</select>
<br />
<div id="resultDiv">
<div th:substituteby="select_ajax::selectAjaxBody" th:fragment="selectAjax"></div>
</div></form>
この 「<div th:substituteby="select_ajax::selectAjaxBody" th:fragment="selectAjax"></div>」の部分が、下の段のプルダウンに置き換わります。
その置き換わるプルダウンのHTML本体は、「select_ajax.html」に書きます。
select_ajax.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Insert title here</title>
</head>
<body>
<select id="singleSelectAjax" name="selectedItemAjax" th:fragment="selectAjaxBody">
<option value="">---</option>
<option id="ajaxOption" th:each="item : ${selectAjaxItems}" th:value="${item.value}" th:text="${item.value}" th:selected="${item.value} == *{selectedItem}">singleSelect</option>
</select>
</body>
</html>
「th:fragment="selectAjaxBody"」がポイントです。
hello3.htmlの「th:substituteby="select_ajax::selectAjaxBody"」という部分は、select_ajax.htmlのth:fragment="selectAjaxBody"で示される範囲のHTMLで置き換えられることを意味します。
コントローラのメソッドをキックする処理
プルダウンが選択された時に、コントローラクラスのメソッドをキックする処理は、hello3.htmlにjavascriptとして書きます。
<script>
<!--
$(function() {
// Ajax通信テスト ボタンクリック
$("#singleSelect").change(function() {
event.preventDefault();
// outputDataを空に初期化
$.ajax({
type : "GET",
url : "getTestData",
dataType : "html",
success : function(data,status,xhr) {
$("#resultDiv").html(data);
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
alert("error:" + XMLHttpRequest + "/" + textStatus + "/" + errorThrown);
}
});
});
});
//-->
</script>
普通のjQueryのajaxです。 $("#resultDiv").html(data);で、id="resultDiv"のDivの中身を書き換えています。
このdataには、select_ajax.htmlの中でthymeleafのth:each命令を使って記述されていた<option>~</option>の部分が、データをセットされて展開済のHTMLとなってはいってきます。
普通に考えたら、コントローラクラスでHTMLに展開したのかな?と思ってしまうのですが、実はコントローラクラスでも、HTMLを組み立てるような処理はしてません。
jQueryの$Ajaxから呼ばれるコントローラクラスのメソッド。
@RequestMapping(value = "getTestData", method = RequestMethod.GET)
public String getTestData(ModelMap model) {
model.addAttribute("selectAjaxItems",getSelectedAjaxItems());
return "hello3::selectAjax";
}
やっているのは、addAtributeでデータを渡して、 returnしているだけです。HTMLの編集もなにもやってませんよね。
処理の肝になる部分
ポイントは、「"hello3::selectAjax";」です。
これは、hello.htmlの「th:fragment="selectAjax"」を指してます。
hello3.htmlの"selectAjax"をめざしていったら、th:substituteby="select_ajax::selectAjaxBody"があるので、一旦、select_ajax.htmlにうつって、そこで生成したHTMLを、$Ajaxの戻り値のdataにセットして戻すことで、当初のターゲットを置き換えるという非常に複雑な動きをしています。
動きがイメージできるとすっきりAjaxが実現できます
このへんが最初なかなかイメージできなくて大変でした。
本とかみても、ちゃんと書いてあるのがなかったですしね。
でも、わかってしまえば、非常にシンプルな書き方ですっきりAjaxが実現できて、JSPでやるより気に入ってます。
getSelectedAjaxItems()の例
ちなみに、getSelectedAjaxItems()の例も書いておきます。
今回はとても適当ですが、実際にはここでDBからデータをとってきたりすると思ってください。
private Map<String,String> getSelectedAjaxItems(){
Map<String, String> selectMap = new LinkedHashMap<String, String>();
selectMap.put("key_A", "Ajaxで取得した選択肢A");
selectMap.put("key_B", "Ajaxで取得した選択肢B");
selectMap.put("key_C", "Ajaxで取得した選択肢C");
selectMap.put("key_D", "Ajaxで取得した選択肢D");
selectMap.put("key_E", "Ajaxで取得した選択肢E");
return selectMap;
}
こんな感じで。
STS +Spring Boot+thymeleaf 関連記事
入力画面に関連する記事
参照画面・画面遷移に関連する記事
参照画面:テーブルを使い、行毎に色分けした一覧表を表示する。
入力チェックに関連する記事
入力チェック:@Patternと正規表現で独自チェックする。
入力チェック用アノテーション定義を自分で作る。(独自実装版)
データアクセス・その他に関連する記事