htmxを使ってみた-(8)要素の変更-

## hx-swap属性による、要素の置換方法
サーバーからHTML形式の返事が来たときに、hx-target属性で指定された（指定しなければ、自分自身）要素を、[ht-swap属性に指定された方法](https://htmx.org/docs/#swapping)で変更します。
| swap指定 | 要素の置換方法 |
|:-|:-|
| innerHTML | デフォルト。要素の中身を変える |
| outerHTML | 要素自身を変える |
| afterbegin | 要素の中の最初の子の前に追加します |
| beforebegin | 要素の前に追加します |
| beforeend | 要素内の最後の子の後に追加します |
| afterend | 要素の後に追加します |
| delete | 要素を削除 |
| none | 何もしない |

練習プログラムでは、
```HTML:html04.j2
<form hx-post="/add_institution" hx-target="#add_btn" hx-swap="beforebegin">
```
とし、hx-swap属性に"beforebegin"を指定して、hx-target属性のid="add_btn"の前に、サーバーからの返事を追加しています。
追加される方(id="add_btn")は、
```HTML:html00.j2
<tr id="add_btn" hx-on::before-swap="change_institution(event)">
```
とし、要素が書き換えられる前に、hx-on属性の指定に従ってchange_institution()関数を起動しています。

## AJAXの戻り値の評価
サーバーのデータを、変更・削除・追加する場合、何らかのエラーが起こることがあります。
htmxはサーバーからの応答で、要素の書き換えを行いますので、書き換える前に、処理が成功したかどうかを判断する必要があります。

:::note info
以下は、AJAXレスポンスを処理する１手法です。
他にもっと良い方法があると思います。（このような方法しか思いつきませんでした）
:::

練習プログラムでは、
```HTML:html00.j2
<tr id="add_btn" hx-on::before-swap="change_institution(event)">
```
の hx-on::before-swap で　change_institution()関数を指定し、AJAXの戻り値を評価します。

:::note alert
before-swapイベントで間違えたこと。
**htmxの属性は付けたタグに作用する。**
hx-target属性で指定した要素にhx-on::before-swapを付けなければならない。
:::
最初、「AJAXの戻り値で、要素が書き換えられる前に評価する」ために、
```HTML
<form hx-post="/add_institution" 
hx-target="#add_btn" 
hx-swap="beforebegin"
hx-on::before-swap="change_institution(event)"
>
```
と書きました。
目的としたことは、
1. formが送信されると、
1. hx-post属性により、HTTPのPOSTメソッドで、サーバーの/add_institutionにアクセスし、
1. hx-target属性により、サーバーからの応答で、idに"add_btn"を持つタグの中身を、
1. hx-swap属性の指定した方法（beforebegin）で書き換える前に、
1. hx-on属性の指定（before-swap）により、戻り値の評価ルーチン（change_institution()）を動かす

でした。

上記の場合、 **hx-targetで自身とは違う要素を指定しています** ので、自身はAJAXの戻り値で書き換えられることはなく、before-swapイベントが発火しません。
**hx-on::before-swap=""は、hx-target=""で指定した要素に付ける必要があります。**

## 戻り値を評価する関数
change_institution()関数は、p00.jsにあります。
```JavaScript:p00.js
function change_institution(event) {
	close_dialog();
	if (event.detail.xhr.status == 200) {
		// 成功時の処理
		responseText = event.detail.xhr.responseText;
		if (responseText == 'データを削除しました') {
			return;
		}
		if (!responseText.includes('<tr')) {
			alert(responseText);
			console.table(event.detail.xhr);
			event.preventDefault();
		}
	} else {
		// 失敗時の処理
		alert("サーバーとの通信に失敗しました");
		console.table(event.detail.xhr);
		event.preventDefault();
	}
}
```
event引数に[before-swapイベントの値](https://htmx.org/events/#htmx:beforeSwap)が入ってきます。
練習プログラムでは、
1. event.detail.xhr.statusを評価して、
1. サーバーで問題なければ、帰ってきた内容を吟味します。
1. もし、帰ってきたデータに\<tr がなければ、変更・削除が失敗した（他分別のPCで書き換えられている）として、event.preventDefault()関数でJavaScriptの実行を中止＝要素を書き換えない＝で終わります。
1. event.detail.xhr.statusでサーバーの処理で問題がある場合、エラーを出して処理を中止します。

練習プログラムでは、「施設追加」の行の上に、新しいデータが表示されます。

## 関連記事一覧
[htmxを使ってみた-(1)htmxの基本-](https://qiita.com/Final1900/items/49a8ac6f27a2427f6306)
[htmxを使ってみた-(2)準備-](https://qiita.com/Final1900/items/9e46fd6630e4bdf90a73)
[htmxを使ってみた-(3)ルート関数-](https://qiita.com/Final1900/items/293a0c8b42465bbb5142)
[htmxを使ってみた-(4)htmxを使う-](https://qiita.com/Final1900/items/f745c4cc34c8d36548f7)
[htmxを使ってみた-(5)HTMLのdialog-](https://qiita.com/Final1900/items/8584ead01e9c842cc60f)
[htmxを使ってみた-(6)データの表示-](https://qiita.com/Final1900/items/33df506cbeb5979c3cfc)
[htmxを使ってみた-(7)データ追加-](https://qiita.com/Final1900/items/a8206948e6d9ac98f105)
[htmxを使ってみた-(8)要素の変更-](https://qiita.com/Final1900/items/aefc518dacbfaf5d9a2a)
[htmxを使ってみた-(9)ページの再読み込み-](https://qiita.com/Final1900/items/783284ff1ad1d02810d5)
[htmxを使ってみた-(10)データの変更-](https://qiita.com/Final1900/items/9541c05d392b137266f3)
[htmxを使ってみた-(11)データベースの排他制御-](https://qiita.com/Final1900/items/db2a48748cd45262ac8b)
[htmxを使ってみた-(12)確認ダイアローグ-](https://qiita.com/Final1900/items/08e1fb3608d3cf0cbc8c)
[htmxを使ってみた-(13)データ削除-(最終)](https://qiita.com/Final1900/items/5389a4890e0d08549810)