アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うこと。

Ajax:プルダウンリストの内容を画面遷移なしに更新する STS 3.8.3(Spring Boot 1.5.1)+thymeleaf

今回は、SpringBoot+thymeleafでAjaxを使って、画面遷移せずに、画面の一部を更新する「非同期処理」をやります。

  

jQueryの$Ajaxの仕組みを使うと、比較的容易に処理は書けますが、SpringBoot+thymeleafの機能を使っているHTMLの一部を書き換えるのは、JSPとは違った一手間が必要になります。

 

今回はそれをやってみます。

 

このような処理で、一番よくあるのが、都道府県の選択にあわせて、適切な市区町村のリストに更新するようなパターンですので、それをイメージしてサンプルを作ります。

 

まず、動作イメージです。

 

こういう2段のプルダウンを用意します。

f:id:arakan_no_boku:20170405220300j:plain

 

そして、上のプルダウンの選択で、画面遷移なく下のプルダウンに選択肢を表示させます。

f:id:arakan_no_boku:20170405220557j:plain

 

これを実現するための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>

 

普通のjQueryajaxです。 $("#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が実現できて、JSPでやるより気に入ってます。

 

ちなみに、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  3.8.3(Spring Boot 1.5.1)+thymeleaf 関連記事

 

入力画面に関連する記事

reCAPTCHA V2をでロボットによる投稿を防ぐ

画像をSUBMITボタン代わりに使う

ラジオボタンとラジオボタングループを使う 

ラジオボタンとラジオボタングループを使う 

チェックボックスを使う。 

HTMLのタグの閉じ忘れで例外が発生する!

プルダウンリストとマルチセレクトボックスを使う。

今度はテキストエリアで複数行入力する。 

テキストボックスの入力と基本的なチェックを使う。

 

参照画面・画面遷移に関連する記事

参照画面:テーブルを使い、行毎に色分けした一覧表を表示する。 

参照画面:条件に一致した時のみHTML要素を出力する。

セッションを使って画面間で情報を受け渡す 

画面遷移:GET時のリクエストパラメータを受け取る 

日本語しか使わなくても、i18N対応はする意味がある。

 

入力チェックに関連する記事

入力チェック:未入力時に空文字が渡される仕様を回避する。 

入力チェック:@Patternと正規表現で独自チェックする。

入力チェック:アノテーション定義を自分で作る。(再利用版)

入力チェック用アノテーション定義を自分で作る。(独自実装版)

入力チェック:複数項目の相関チェックアノテーションの作り方

 

データアクセス・その他に関連する記事

データアクセス:Jprepositoryを使って簡単にCRUDする。 

データアクセス:ネイティブなSQL文を実行する 

クラスパス内の静的ファイルにアクセスする 

SpringBootだとログの書き出しも楽ちんです。 

SpringBootプロジェクトでJUNIT4を使った単体テストをする。

 

f:id:arakan_no_boku:20170404203859j:plain