スポンサードリンク


jQueryのclone関数の思わぬバグ!セレクトボックス実装時は注意!入力値のコピー処理がnullになる不具合の解決方法!

    jQueryのライブラリの中で、clone関数というHTMLオブジェクトをコピーする便利なものがあります。

    ウェブページを構築する際に、利用者の入力内容に応じて、
    リクエストさせたいデータ項目をフレキシブルに切り替えさせたいときによく利用しています。

    具体的には、divコンテナに入力情報用のHTMLオブジェクトを記述し、
    サブミット処理などでリクエストを送信する際に、
    divコンテナの子要素のオブジェクトをformタグ内にクローンさせて、入力情報を送信させるというものです。

     

    ちょっと大げさな例を紹介しますが、
    シンプルな処理なら以下の画像のように、formタグを複数用いてデータ送信するだけで済みます。

    jquery clone セレクトボックス

    ところが送信先の処理がどれもほぼ共通化できる状態で、
    わざわざ複数に分けてコーディングするとあまりかっこよくありませんよね。

    さらに大量の入力データを扱う場合、ソースが増え見づらいし、管理しづらいのが問題です。

    これを解決してくれるのに便利なのがclone関数です。

    jquery clone セレクトボックス

    formタグをひとつに集約し、formタグの子要素は指定しません。(指定する場合もあり)

    各種入力内容のオブジェクトは例えばdiv要素のコンテナにまとめてしまい、
    入力した内容に応じて、div要素内の入力情報をサブミット時にformに移してあげれば、かなりスッキリしますね。

    ポップアップ入力やその他複雑な処理を実装する際にデータの移し替えに利用していますが、
    clone関数を使ったことある人なら知ってる思わぬ不具合があります。

     

    セレクトボックスの入力値がjQueryのclone関数でnullになる不具合

    jQueryの最新バージョンを使っていないので、
    もしかしたら修正されているかもしれませんが、まだまだ旧バージョンのjQueryを使う機会は多いと思います。

    実はこのclone関数の不具合でセレクトボックスのオブジェクトをコピーすると、
    選択入力された値がコピー先で反映されずに空状態になってしまいます。

    公式の不具合のようで、clone関数の1行のコーディングではセレクトボックスの入力値がコピーされないんです。

    セレクトボックスそのものはコピーできても、選択した入力値を保持していません。
    どうやらこの問題はブラウザによって挙動が違うようでjQuery側のプラグインで制御できないみたいなんです。

     

    試しに以下のようなHTMLに対してスクリプトコードを記述します。

     

    clone関数実行前のHMTL

     

    スクリプトコード

     

    スポンサードリンク

     

    clone関数実行後のHMTL

     

    HTMLオブジェクトはコピーされるもののセレクトボックスのselected属性が引き継がれません。
    このまま気が付かずにフォームのサブミット処理が実行されてしまうと、
    遷移先のページでセレクトボックスに対応する変数がnull値になってしまいます。

    clone関数にオプションを付け加えることで対策できないか調べてみましたが、
    どうやら打つ手なしのようです。

    仕方ないのでクローン化した後に各コントロールの入力値を引き継ぐように対応させました。

     

    セレクトボックスの入力値を引き継がせるスクリプトを後述

    あまり堅実的ではないですが、clone関数だけでは頼りないので
    スクリプトコードを以下のように変更して対応させました。

     

    スクリプトコード

     

    上記のソースコードはあくまでサンプルなので、HTMLの構造によっては対応できないものもあります。
    適宜ソースを調整して値渡しをする工夫が必要ですね。

    あとは同名のname属性のセレクトボックスが存在する場合は対応できないので、その場合もソースの改変が必要です。

     

    jQueryのclone関数の引数true/falseとremove関数の組み合わせに注意

    clone関数内の引数でboolean型を指定しますが、この真偽値はtrueならコピー元のイベントハンドラを引き継ぎます。つまり、元のイベントハンドラを参照します。

    falseなら引き継ぎは行われません。

    さて今回のようにサブミット処理時に特定のデータをクローン化させて
    データ送信を行なう場合でも、処理実行後に画面を遷移しないようにすることってありますよね。

    formaタグにtarget属性を指定した場合
    サブミットではなくajaxで非同期通信する場合などです。

    この時、クローン化させたHTMLオブジェクトを削除しておかないと、
    処理を実行した回数分オブジェクトのクローンが生成されておかしなことになります。

    なので処理後にremove関数などでコピー先HTMLオブジェクトを削除しておきます。
    が、ここで問題があります。

    clone関数の引数をtrue指定し、remove関数を実行するとイベントハンドラまで削除されます。
    要するに、コピー元のイベントまでも削除されてしまうということです。

    例えば、クリックイベントが削除されてしまうなどなど・・・。

    イベントハンドラを別々にしたい場合は、clone関数利用時にはfalseを指定しておきましょう。

      The following two tabs change content below.
      よっき プロフィール画像
      パソコンが大好きな青年。職業はプログラマ/SE。 フリーランスとしてウェブサイトの構築・保守の業務に従事。専門学校とパソコンスクールで講師も担当。幼少期からパソコンが大好きで、趣味がそのまま仕事に転じた。自作PCの魅力に惹かれたのは学生時代の頃。自作PC専門ブログで、お得な情報を紹介しています。

      スポンサードリンク


      コメントを残す




      CAPTCHA


      このページの先頭へ