どうも、kotoriです。
みなさん、webアプリケーションなどでユーザーが動的に入力項目を追加・削除出来るフォームを見かけたことありませんか。
例えばこんな感じのフォームです!
サンプル
ベーシック認証が掛かってます。
ユーザ名:admin
パスワード:4ndancom
今日は項目数を自由に可変できるフォームの実装方法を詳しく紹介します!
jQueryで実装します!
別に詳しい解説なんていらないからサンプルソース見せろって方は上のサンプルのソースを参照してください!
フォームの追加機能を実装するならjQueryのclone()を使おう
フォームを追加する機能を実装するためにはjQueryのcloneを利用すると便利です!
clone()は指定した要素のクローンを作成し変数に格納して色々操作することができます。
まさに、フォームの項目を追加・削除するボタンを実装するのに最適な関数です!
フォームの追加・削除を実装するにあたり考慮すべき事
フォームの追加・削除機能を実装するために、いくつか考慮しておく必要がある事があります。
それは
- フォームのname属性や要素のクラス名に数字を含め、追加・削除されるフォーム項目を番号で管理する
- 追加する時は、フォームのname属性や要素のクラス名の番号に1を足す
- 削除する時は、フォームのname属性や要素のクラス名の番号を振りなおす
の3つです。
フォームのname属性や要素のクラス名に数字を含め、追加・削除されるフォーム項目を番号で管理する
例えば、冒頭で紹介したサンプルでは下記のようにHTMLをコーディングしています。
<div class="box" data-formno="0" style="border:dashed 1px #ccc"> <p class="no">1</p> <p> 【名前】<br> <input type="text" name="input[0]" class="namae"> </p> <p> 【お問い合わせ】<br> <textarea name="textarea[0]" cols="30" rows="10" class="toiawase"></textarea> </p> <a class="deletformbox">削除</a> </div> <p><a class="addformbox">追加</a></p>
「box」クラス単位でフォームを追加・削除できるサンプルのHTMLのコーディングです。
動的に追加・削除の操作をユーザーができる機能を実装するのであれば、要素の識別方法として連番のクラス名などを付けるのが定石です。
このサンプルでは、クラス名の代わりにdata属性で連番管理しています。
「data-formno」の部分ですね。
また、項目数が可変するフォームは値を配列で管理するのが定石です。
値を配列で管理するフォームのname属性は「input[0]」のような形になります。項目追加による2つ目のname属性は「input[1]」のような具合で、番号を一つずつ足していきます。
このようなname属性の付け方をすることでname属性「input」が配列となり複数の値をname属性「input」に格納することができます。
これ大変便利な知識なので、知らなかった人は是非覚えて帰ってください!
追加する時は、フォームのname属性や要素のクラス名の番号に1を足す
前項の「フォームのname属性や要素のクラス名に数字を含め、追加・削除されるフォーム項目を番号で管理する」で、項目数が可変する場合は番号で管理するのが便利という話をしたので、「追加」ボタンをクリックした時の動作でclone()でクローンした要素のname属性やクラス名の番号を+1にする方法を考える必要があります。
削除する時は、フォームのname属性や要素のクラス名の番号を振りなおす
フォームの削除機能を考慮するなら、管理している番号に気を使う必要があります。具体的には「削除」ボタンによってフォームが削除されたタイミングで管理番号を最初から降りなおすことが必要です。
何故なら、例えば「追加」ボタンにより3つのフォームが
フォーム1
フォーム2
フォーム3
のような番号で存在していたとして、「フォーム2」の「削除」ボタンがクリックされた場合、何も考えなければ
フォーム1
フォーム3
と番号が歯抜けになってしまいます。
こうなると番号で管理している意味がないので、「削除」ボタンがクリックされたら1番目のフォームから番号を振りなおす動作を入れる必要があります。
フォームを動的に追加する
ではここからは具体的なコードを見ながら解説していきます。
まずフォームを動的に追加するボタンをクリックした時のscriptはこのようになります。
//追加 $('.addformbox').click(function() { //クローンを変数に格納 var clonecode = $('.box:last').clone(true); //数字を+1し変数に格納 var cloneno = clonecode.attr('data-formno'); var cloneno2 = parseInt(cloneno) + 1; var cloneno3 = parseInt(cloneno) + 2; //data属性の数字を+1 clonecode.attr('data-formno',cloneno2); //数値 clonecode.find('.no').html(cloneno3); //name属性の数字を+1 var namecode = clonecode.find('input.namae').attr('name'); namecode = namecode.replace(/input\[[0-9]{1,2}/g,'input[' + cloneno2); clonecode.find('input.namae').attr('name',namecode); var namecode2 = clonecode.find('textarea.toiawase').attr('name'); namecode2 = namecode2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + cloneno2); clonecode.find('textarea.toiawase').attr('name',namecode2); //HTMLに追加 clonecode.insertAfter($('.box:last')); });
では一つずつ確認してきます。
//クローンを変数に格納 var clonecode = $('.box:last').clone(true);
初めにjQueryのclone()を使用し、一番最後の「.box」クラスの要素のクローンをclonecode変数に格納します!
//数字を+1し変数に格納 var cloneno = clonecode.attr('data-formno'); var cloneno2 = parseInt(cloneno) + 1; var cloneno3 = parseInt(cloneno) + 2;
格納したクローンの「data-formno」の値をcloneno変数に格納します。
そしてcloneno変数を+1してcloneno2に格納します。
更に+2した数値もcloneno3に格納します。
何故+1した変数と+2した変数を用意するのかというと、
プログラムの世界での配列の数値の始まりは「0」ですが、私たち人間の目に入るデザインの中での最初の数字は「1」です。きっとHTML上は一番最初のフォーム項目は「フォーム1」とか「タイトル1」とか1の数字を付けて表示すると思います。
つまり、プログラムの世界と現実の世界で、一番最初の数字に差異があるのです。
そのため、+1した変数と+2した変数の二つを用意しています。
//data属性の数字を+1 clonecode.attr('data-formno',cloneno2); //数値 clonecode.find('.no').html(cloneno3);
「data-formno」の値を+1した数値に置き換えます。これがプログラムの世界の数字です。
表示する番号も合わせて置き換えます。これが現実の世界の数字です。
//name属性の数字を+1 var namecode = clonecode.find('input.namae').attr('name'); namecode = namecode.replace(/input\[[0-9]{1,2}/g,'input[' + cloneno2); clonecode.find('input.namae').attr('name',namecode); var namecode2 = clonecode.find('textarea.toiawase').attr('name'); namecode2 = namecode2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + cloneno2); clonecode.find('textarea.toiawase').attr('name',namecode2);
name属性の配列の番号を足し上げるためには、正規表現を使用します。
正規表現のことを話し出すと切りがないので、name属性で配列を扱える「input[0]」の様な値の数値を足し上げるための正規表現はこれなんだと理解してもらえればと思います。
サンプルではinputとtextareaの2項目を用意したので、それぞれのname属性の数字を足し上げます。
//HTMLに追加 clonecode.insertAfter($('.box:last'));
最後に、「.box」クラス要素の最後にクローンした要素を挿入します。
これで「追加」ボタンの実装は完了です。
フォームを動的に削除する
フォームを動的に削除するボタンに関しても具体的なコードを見ながら解説していきます。
//削除 $('.deletformbox').click(function() { //クリックされた削除ボタンの親のクラス名を取得 $(this).parents(".box").remove(); var scount = 0; //番号振り直し $('.box').each(function(){ var scount2 = scount + 1; //data属性の数字 $(this).attr('data-formno',scount); $('.no',this).html(scount2); //input質問タイトル番号振り直し var name = $('input.namae',this).attr('name'); name = name.replace(/input\[[0-9]{1,2}/g,'input[' + scount); $('input.namae',this).attr('name',name); var name2 = $('textarea.toiawase',this).attr('name'); name2 = name2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + scount); $('textarea.toiawase',this).attr('name',name2); scount += 1; }); });
一つずつ見ていきましょう!
//クリックされた削除ボタンの親要素を削除 $(this).parents(".box").remove();
まずクリックされた削除ボタンの親要素の「.box」を削除します。
var scount = 0;
番号を振りなおすための変数を準備します。
$('.box').each(function(){ var scount2 = scount + 1; //data属性の数字 $(this).attr('data-formno',scount); $('.no',this).html(scount2); //input質問タイトル番号振り直し var name = $('input.namae',this).attr('name'); name = name.replace(/input\[[0-9]{1,2}/g,'input[' + scount); $('input.namae',this).attr('name',name); var name2 = $('textarea.toiawase',this).attr('name'); name2 = name2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + scount); $('textarea.toiawase',this).attr('name',name2); scount += 1; });
ここでフォームのname属性や要素のクラス名の番号を振りなおします。
「$(‘.box’).each」で存在する.box要素に対して番号振りなおす処理を繰り返し実行します!
コメントで「data属性の数字」と書いている部分でdata属性や表示する番号を振りなおしています。
コメントで「input質問タイトル番号振り直し」となっている部分は、正規表現を使ってinputのname属性の番号を振りなおしています。
ここも、name属性で配列を扱える「input[0]」の様な値の数値を足し上げるための正規表現はこれなんだと理解してもらえればと思います。
最後の「scount += 1」で番号を1ずつ足しています。
フォームを動的に追加・削除する実装まとめ
それではまとめとして全コードを載せておきます。
<!doctype html> <html> <head> <meta charset="utf-8"> <title>フォーム入力項目を動的に追加・削除【jquery】:サンプル</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript"> $(function() { //追加 $('.addformbox').click(function() { //クローンを変数に格納 var clonecode = $('.box:last').clone(true); //数字を+1し変数に格納 var cloneno = clonecode.attr('data-formno'); var cloneno2 = parseInt(cloneno) + 1; var cloneno3 = parseInt(cloneno) + 2; //data属性の数字を+1 clonecode.attr('data-formno',cloneno2); //数値 clonecode.find('.no').html(cloneno3); //name属性の数字を+1 var namecode = clonecode.find('input.namae').attr('name'); namecode = namecode.replace(/input\[[0-9]{1,2}/g,'input[' + cloneno2); clonecode.find('input.namae').attr('name',namecode); var namecode2 = clonecode.find('textarea.toiawase').attr('name'); namecode2 = namecode2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + cloneno2); clonecode.find('textarea.toiawase').attr('name',namecode2); //HTMLに追加 clonecode.insertAfter($('.box:last')); }); //削除 $('.deletformbox').click(function() { //クリックされた削除ボタンの親要素を削除 $(this).parents(".box").remove(); var scount = 0; //番号振り直し $('.box').each(function(){ var scount2 = scount + 1; //data属性の数字 $(this).attr('data-formno',scount); $('.no',this).html(scount2); //input質問タイトル番号振り直し var name = $('input.namae',this).attr('name'); name = name.replace(/input\[[0-9]{1,2}/g,'input[' + scount); $('input.namae',this).attr('name',name); var name2 = $('textarea.toiawase',this).attr('name'); name2 = name2.replace(/textarea\[[0-9]{1,2}/g,'textarea[' + scount); $('textarea.toiawase',this).attr('name',name2); scount += 1; }); }); }); </script> </head> <body> <div class="box" data-formno="0" style="border:dashed 1px #ccc"> <p class="no">1</p> <p> 【名前】<br> <input type="text" name="input[0]" class="namae"> </p> <p> 【お問い合わせ】<br> <textarea name="textarea[0]" cols="30" rows="10" class="toiawase"></textarea> </p> <a class="deletformbox">削除</a> </div> <p><a class="addformbox">追加</a></p> </body> </html>
サンプルも載せておきます。
ユーザ名:admin
パスワード:4ndancom
細かい説明をつらつらと書きましたが、サンプルコードを見るのが一番早いですからね!
フォームを動的に追加・削除する実装のお役に立てれば嬉しいです!
ここまで読んでいただきありがとうございました!