0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ThymeleafとJavaScriptでチェックボックスの値が意図しない`"on"`になる問題とその解決策

Posted at

Web開発において、ThymeleafとJavaScriptを使ったフォーム処理で、ネストしたDTOのInteger型フィールドをチェックボックスにバインドした際、値が0であるはずなのにJSONで"on"が送信される問題が発生することがあります。この記事では、問題の原因を詳細に分析し、確実な解決策を紹介します。

問題の概要

チェックボックスに対応するDTOのフィールド(例:subDto.editedFlag)がInteger型で、0または1を保持する設計だとします。しかし、フォーム送信時にJavaScriptで生成したJSONでは、editedFlagの値が意図した0ではなく"on"になってしまうケースがあります。

問題の核心は、JavaScriptがチェックボックスの「状態(オン/オフ)」ではなく、「value属性の値」を取得している点にあります。この挙動は、Thymeleafが生成するHTMLとJavaScriptの処理の組み合わせによって引き起こされます。


問題の原因

以下の2つの要因が主な原因です。

原因1:JavaScriptでの値の取得方法が不適切

チェックボックスの値を取得する際、以下のようなコードを使用している場合、問題が発生します。

// 誤ったコード例
formObject.subDto.editedFlag = document.getElementById('your-checkbox-id').value;

このコードでは、チェックボックスのvalue属性の値を取得します。しかし、チェックボックスがチェックされているかどうかに関わらず、value属性の値(またはデフォルト値の"on")が取得されてしまいます。

原因2:Thymeleafによるvalue属性の未出力

Thymeleafテンプレートで、チェックボックスのth:value属性が正しく設定されていない場合も問題の原因となります。たとえば、以下のようなテンプレートを考えてみましょう。

<input type="checkbox" th:field="*{subDto.editedFlag}" th:unchecked-value="0">

この場合、ThymeleafはeditedFlagの値(0または1)に基づいてchecked属性を制御しますが、th:valueが指定されていないため、value属性がHTMLに出力されません。結果として、生成されるHTMLは以下のようになります。

<input type="hidden" name="_subDto.editedFlag" value="0">
<input type="checkbox" id="subDto.editedFlag" name="subDto.editedFlag">

この状態で、JavaScriptが.valueを参照すると、ブラウザはvalue属性がない場合にデフォルト値"on"を返します。そのため、editedFlag0であっても、JSONに"on"が設定されてしまいます。


解決策

この問題を解決するには、JavaScriptでチェックボックスの状態checkedプロパティ)を正しく判定し、適切な値を設定する必要があります。以下に具体的な手順を示します。

1. Thymeleafテンプレートの確認

まず、Thymeleafテンプレートでth:valueid属性が正しく設定されていることを確認します。

<input type="checkbox" id="editedFlag"
       th:field="*{subDto.editedFlag}" 
       th:value="1" 
       th:unchecked-value="0" />
  • th:field="*{subDto.editedFlag}":DTOのフィールドにバインド。
  • th:value="1":チェックボックスがオン時に送信される値。
  • th:unchecked-value="0":チェックがオフ時の値。
  • id="editedFlag":JavaScriptからアクセスするためのユニークなID。

2. JavaScriptの修正

JavaScriptでは、チェックボックスのcheckedプロパティを使用して状態を判定し、1または0を明示的に設定します。以下は、フォームデータをJSONとして送信するサンプルコードです。

async function submitAsJson() {
    const formObject = /*[[${mainForm}]]*/ null;

    // テキスト入力欄の取得
    formObject.name = document.getElementById('name').value;
    formObject.subDto.detail = document.getElementById('detail').value;

    // チェックボックスの状態を取得
    const checkbox = document.getElementById('editedFlag');
    formObject.subDto.editedFlag = checkbox.checked ? 1 : 0;

    // fetch APIで送信
    try {
        const response = await fetch('/api/save', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(formObject)
        });
        // 後続処理
        console.log('Success:', await response.json());
    } catch (error) {
        console.error('Error:', error);
    }
}

ポイント

  • checkbox.checkedは、チェックボックスがオンならtrue、オフならfalseを返します。
  • 三項演算子checkbox.checked ? 1 : 0により、チェック状態に応じて1または0editedFlagに設定。
  • これにより、JSONには常に数値の1または0が送信されます。

原因と解決策のまとめ

原因 メカニズム
JavaScriptの不適切な値取得 .valueプロパティを使用したため、チェック状態ではなくvalue属性値(またはデフォルトの"on")を取得。
value属性の欠如 th:valueが設定されていないため、HTMLにvalue属性が出力されず、ブラウザがデフォルト値"on"を返す。
解決策 詳細
Thymeleafテンプレートの修正 th:value="1"th:unchecked-value="0"を明示的に設定し、id属性を追加。
JavaScriptの修正 .checkedプロパティを使用してチェック状態を判定し、1または0をセット。

追加の考慮点

  • バリデーション:サーバー側で受信したJSONのeditedFlag0または1であることを検証すると、予期しない値を防げます。
  • デフォルト値の確認:DTOの初期値が正しく設定されているか確認し、Thymeleafが意図通りにchecked属性を生成しているかを検証。
  • デバッグのコツ:ブラウザの開発者ツールで生成されたHTMLを確認し、value属性やchecked属性が正しく出力されているかチェック。

結論

チェックボックスの値が"on"になってしまう問題は、JavaScriptがvalue属性を参照することと、Thymeleafでvalue属性が正しく設定されていないことの組み合わせによって発生します。解決策として、Thymeleafでth:valueidを適切に設定し、JavaScriptで.checkedプロパティを使用してチェック状態を判定することで、意図した0または1をJSONに確実に送信できます。このアプローチはシンプルかつ確実で、同様の問題を防ぐためのベストプラクティスと言えるでしょう。

関連リソース

この解決策を実装することで、チェックボックスの値を正確に扱い、安定したフォーム処理を実現できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?