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?

【実務で使えるJSF】Ajax後にJavaScriptを再初期化する|DOM再描画後の処理をまとめる

0
Posted at

🎯 やりたかったことは?

JSFのAjaxで画面の一部を更新したあと、
その部分に対してJavaScriptの処理も使いたい場面がありました。

例えば、

  • クリックイベントを登録する
  • 入力項目の状態を初期化する
  • JavaScript側でDOMを取得する
  • プラグインや独自UIを初期化する

といった処理です。

最初の画面表示では問題なく動いていても、
Ajaxで再描画したあとだけ動かなくなることがあります。

JSFのAjaxではDOMが差し替わることがあるため、
JavaScript側の初期化も再度必要になるケースがあります。


🚀 急いでいる人向け

JSFのAjax後にJavaScriptの処理が効かなくなった場合は、

Ajaxのrenderで対象DOMが差し替わっていないか

を確認します。

DOMが差し替わった場合、
古いDOMに対して行った

element.addEventListener(...);

などの設定は新しいDOMには引き継がれません。

Ajax完了後に、

function ajaxSuccess(event) {

    if (event.status !== "success") {
        return;
    }

    initialize();
}

のように再初期化します。


💡 この記事で分かること

  • JSFのAjax後にJavaScriptが効かなくなる理由
  • render によるDOM差し替えの影響
  • Ajax完了後に初期化処理を呼ぶ方法
  • 初期化処理を関数にまとめる理由
  • イベントの二重登録を防ぐ考え方

はじめに

JSFで画面を作っていると、
サーバー側のAjax処理とJavaScriptを組み合わせることがあります。

例えば、

const button = document.getElementById("sampleButton");

button.addEventListener("click", () => {
    // 処理
});

のようなイベント登録です。

初期表示では普通に動きます。

ただ、JSFのAjaxでそのボタンを含む領域を render すると、
見た目は同じなのにイベントだけ動かなくなることがあります。

自分も最初は、

JavaScript側の処理が途中で止まった?

と思っていました。

実際にはJavaScriptの問題ではなく、
Ajaxによって対象のDOMそのものが入れ替わっていました。


🔍 なぜ再初期化が必要になるのか

例えば、最初の画面に次のボタンがあるとします。

<button id="sampleButton">
    実行
</button>

JavaScriptから、

const button = document.getElementById("sampleButton");

button.addEventListener("click", () => {
    console.log("click");
});

を登録します。

この時点では、

DOM A
└─ clickイベントあり

という状態です。

その後、JSFのAjaxでこの領域を再描画します。

<f:ajax
    execute="@this"
    render="buttonArea" />

すると、ブラウザ上では対象DOMが置き換えられます。

DOM A
↓ 削除

DOM B
↓ 新しく生成

見た目:同じ
id:同じ
イベント:なし

新しく生成されたDOM Bには、
DOM Aへ登録したイベントは存在しません。


✅ 初期化処理を関数にまとめる

こういう処理は、
最初から初期化関数としてまとめておくと扱いやすいです。

function initialize() {

    const button =
        document.getElementById("sampleButton");

    if (!button) {
        return;
    }

    button.addEventListener("click", () => {
        console.log("click");
    });
}

初期表示時に、

initialize();

を呼びます。

Ajax後にも同じ関数を呼びます。


Ajax完了後に再初期化する

JSF Ajaxの完了後に処理を入れる場合は、
Ajaxのステータスを確認してから初期化します。

例えば、

ajaxSuccess(event) {

    if (event.status !== "success") {
        return;
    }

    this.initialize();
}

のようにします。

実際には、
すべてのAjaxで毎回呼ぶのではなく、
対象のDOMを再描画したときだけ実行する方が安全です。

ajaxSuccess(event) {

    if (event.status !== "success") {
        return;
    }

    switch (event.source.id) {

        case "samplePage_saveAction":
            this.initialize();
            break;

        default:
            break;
    }
}

⚠️ 何でも再初期化すればいいわけではない

ここで注意したいのが、
イベントの二重登録です。

例えば同じDOMに対して、

button.addEventListener("click", () => {
    console.log("click");
});

を2回実行すると、
クリック時の処理も2回実行されます。

click
click

となります。

AjaxでDOMが置き換わった場合は問題ありません。

新しいDOMなので、
イベントを改めて登録する必要があります。

一方、DOMが置き換わっていないのに
毎回 initialize() を呼ぶと二重登録の原因になります。


💼 実務での使い分け

自分の場合は、

Ajaxでrenderした領域
↓
その中にJavaScriptで初期化している要素があるか

を確認するようにしています。

対象がある場合だけ、

initialize();

を呼びます。

特に確認するのは、

  • addEventListener
  • DOM取得結果を変数に保持している処理
  • JavaScriptで状態を付与している要素
  • 外部ライブラリやUI部品の初期化

あたりです。

逆に、
Ajaxの render 対象外なら再初期化する必要はありません。


📝 まとめ

JSFのAjax後にJavaScriptが動かなくなった場合は、
まずDOMが再描画されていないか確認します。

  • render されたDOMは新しいDOMへ置き換わる
  • 古いDOMへ登録したイベントは引き継がれない
  • JavaScriptの初期化処理は関数にまとめておくと使いやすい
  • Ajax完了後に必要な場合だけ再初期化する
  • DOMが置き換わっていない場合は二重登録に注意する

JSFでは自分でDOMを書き換えた感覚がなくても、
f:ajax render によってDOMが変わっていることがあります。

Ajax後だけJavaScriptの挙動がおかしい場合は、
再描画範囲も確認すると原因を追いやすいです。

0
0
1

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?