こんにちは、エキサイト株式会社の平石です。
今回は、HTMXでhx-get
やhx-post
を使ってリクエストを実行した後に任意のJavaScriptコードを実行する方法をご紹介します。
はじめに
HTMXでは、hx-get
やhx-post
を利用して、リクエストを実行することができます。
そして、レスポンスとして返ってきたHTMLテンプレートで既存のテンプレートの全体または一部を置き換えることができます。
しかし、このリクエストの実行後に任意のJavaScriptコードを実行したい場合もあると思います。
今回は、その方法をブログ記事として残しておきたいと思います。
環境
以下の環境で動作確認をしています。
- Java 21
- Spring Boot v3.2.2
- HTMX v1.9.10
ただし、基本的にはHTMX + (生の)JavaScriptであるため、サーバーサイドの言語がJava以外であっても動作するかと思います。
例
以下のようなControllerを考えます。
@Controller @RequestMapping("sample") public class SamplePageController { private final List<String> stringList = new ArrayList<>(); @GetMapping("/index") public String sampleIndex( Model model ) { model.addAttribute("stringList", stringList); return "sample/index"; } @PostMapping("/add") @ResponseStatus(HttpStatus.CREATED) public String sampleIndex( Model model, String string ) { if (string.isBlank() || string.length() > 10) { throw new ResponseStatusException( HttpStatus.BAD_REQUEST, "bad request" ); } stringList.add(string); model.addAttribute("stringList", stringList); return "elements/sample/strings"; } }
渡された文字列のパラメータをリストに追加し、その結果のリストをテンプレートに渡しています。
ただし、空文字列または文字数が11文字以上であった場合には、ステータスコード400でレスポンスを返します。
次に、テンプレートを記述します。
今回は、Thymeleafを利用しています。
resources/templates/sample/index.html
を以下のように記述します。
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" lang="en"> <head> <title>サンプルページ</title> <script src="/webjars/htmx.org/1.9.10/dist/htmx.min.js"></script> </head> <body hx-boost="true"> <div id="stringList" th:insert="~{elements/sample/strings}"></div> <form id="numberForm" hx-post="/sample/add" hx-target="#stringList" hx-swap="innerHtml"> <input type="text" name="string"> <input type="submit" value="追加"> </form> </body> </html>
また、resources/templates/elements/sample/strings.html
を以下のように記述します。
<ul> <th:block th:each="string : ${stringList}"> <li th:text="${string}"></li> </th:block> </ul>
index.html
内の<div id="stringList" th:insert="~{elements/sample/strings}"></div>
の部分にstrings.html
が挿入されます。
Spring Bootアプリケーションを起動してsample/index
にアクセスすると、以下のようなフォームが表示されます。
フォームに適当に文字列を入力して、「追加」ボタンを押すと上に入力した文字列が追加されます。
リクエスト後にJavaScriptコードを実行する
それでは、「追加」ボタンを押して文字列をリストに追加した後に任意のJavaScriptコードを実行してみます。
今回は、リクエスト後にアラートを出すような処理を追加します。
HTMXのEventsの中にある、htmx:afterRequest
を利用します。
htmx:afterRequest
イベントは、AJAXリクエストが終了したときにトリガーされるイベントです。
hx-on
を使って、このイベントをトリガーにして実行する処理を記述します。
<form id="numberForm" hx-post="/sample/add" hx-target="#stringList" hx-swap="innerHtml" hx-on::after-request="alert('追加しました。')"> <input type="text" name="string"> <input type="submit" value="追加"> </form>
イベントはhtmx:afterRequest
ですが、hx-on
で記述する際にはafter-request
とする必要があります。
また、htmx:afterRequest
のようにHTMX固有のイベントでは、本来はhx-on:htmx:after-request
と書くところをhx-on::after-request
のように省略して記述することができます。
このコードを追加した上で、適当に入力して追加ボタンを押してみます。
アラートが表示され、リクエスト終了後にJavaScriptコードが実行されたことがわかります。
当然ながら、処理を関数として定義してその関数を呼び出すこともできます。
<form id="numberForm" hx-post="/sample/add" hx-target="#stringList" hx-swap="innerHtml" hx-on::after-request="displayAlert()"> <input type="text" name="string"> <input type="submit" value="追加"> </form> <script> function displayAlert() { alert('失敗しました。'); } </script>
また、特別なシンボルとしてevent
を利用することができます。
event.detail
にはそのイベント固有の情報が入っています。
例えば、htmx:afterRequest
では実行されたリクエストのパラメータやパス、レスポンスの情報を参照することができます。
<form id="numberForm" hx-post="/sample/add" hx-target="#stringList" hx-swap="innerHtml" hx-on::after-request="displayAlert(event)"> <input type="text" name="string"> <input type="submit" value="追加"> </form> <script> function displayAlert(event) { if (event.detail.xhr.status === 400) { const string = event.detail.requestConfig.parameters.string; alert("失敗しました。パラメータ`string: " + string + "`が不正です。"); } } </script>
displayAlert
関数にevent
を渡しています。
ここでは、event.detail.xhr.status
でレスポンスのステータスコードを取得しており、ステータスコード400でレスポンスが返ってきた時のみアラートを出すようにしています。
また、event.detail.requestConfig.parameters
でリクエストに使用したパラメータを取得できるので、リクエストパラメータの情報を使ってアラートの内容を補足しています。
この状態で、例えばフォームにToo long string
と入力して「追加」ボタンを押すと以下のようなアラートが出ます。
なお、hx-on
を利用せず、生のJavaScriptを利用して、document
全体やHTML要素に対して直接イベントリスナを追加することもできます。
全てのHTMXリクエストの後に実行したい処理があるといった場合は、こちらを利用しても良いかもしれません。
<script> document.addEventListener('htmx:afterRequest', function (evt) { if (evt.detail.failed) { alert("失敗しました。"); } }); </script>
おわりに
今回は、HTMXでhx-get
やhx-post
を使ってリクエストを実行した後に任意のJavaScriptコードを実行する方法をご紹介しました。
では、また次回。