JQueryを使ってTABLEのを増減する方法

WEBアプリを作ってるとき、例えば↓みたいな入力フォームを作る時がある。


No.入力値
1
2


ソースにするとこんな感じ


<table border="1">
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input type="text" name="input" value="1" /></td></tr>
<tr><td>2</td><td><input type="text" name="input
" value="2" /></td></tr>
<input type="submit" value="登録" />
</table>

こんなフォームでINPUTを動的に変動させる一番シンプルな対処方法は、「+」「-」ボタンを作って、type属性をsubmitにして毎回POSTさせる事ですね。

なのでボタンを追加。


No.入力値
1
2





<table border="1">
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input type="text" name="input" value="1" /></td></tr>
<tr><td>2</td><td><input type="text" name="input
" value="2" /></td></tr>
<input type="submit" name="add" value="+" /> <input type="submit" name="sub" value="-" />
<input type="submit" value="登録" />
</table>

HTMLが静的なので、当然サーバ側で動的にテキストボックスを増減させる処理が必要。


<?php
$input =$_POST['input'];
$c = count($input);
$c++;
for($i=0;$i<$c;$i++){
echo('<input type="text" name="input" />');
}
?>

こんな感じかな。まあ実行してないからバグるかもしれないけど理屈はあってるはず。>

さて、これからが今回の本題です。

Web2.0を追加した2011年代に、静的なHTML+サーバプログラムでいちいち入力フォームを制御ってイケテルの??


    毎    し!       -── ‐-   、  , -─-、 -‐─_ノ   ポ
  小 回    // ̄> ´  ̄    ̄  `ヽ  Y  ,  ´     )   ス え
  学 ポ    L_ /                /        ヽ   ト  |
  生 ス    / '                '           i  !? 毎
  ま ト    /                 /           く    回
  で が    l           ,ィ/!    /    /l/!,l     /厶,
  だ 許   i   ,.lrH‐|'|     /‐!-Lハ_  l    /-!'|/l   /`'メ、_iヽ
  よ さ   l  | |_|_|_|/|    / /__!__ |/!トi   i/-- 、 レ!/   / ,-- レ、⌒Y⌒ヽ
  ね れ   _ゝ|/'/⌒ヽ ヽト、|/ '/ ̄`ヾ 、ヽト、N'/⌒ヾ      ,イ ̄`ヾ,ノ!
   l  る  「  l ′ 「1       /てヽ′| | |  「L!     ' i'ひ}   リ
    の   ヽ  | ヽ__U,      、ヽ シノ ノ! ! |ヽ_、ソ,      ヾシ _ノ _ノ
-┐  は ,√   !            ̄   リ l   !  ̄        ̄   7/
  レ'⌒ヽ/ !    |   〈       _人__人ノ_  i  く            //!
人_,、ノL_,iノ!  /! ヽ   r─‐- 、   「      L_ヽ   r─‐- 、   u  ノ/
      /  / lト、 \ ヽ, -‐┤  ノ  キ    了\  ヽ, -‐┤     //
ハ キ  {  /   ヽ,ト、ヽ/!`hノ  )  モ    |/! 「ヽ, `ー /)   _ ‐'
ハ ャ   ヽ/   r-、‐' // / |-‐ く    |     > / / `'//-‐、    /
ハ ハ    > /\\// / /ヽ_  !   イ    (  / / //  / `ァ-‐ '
ハ ハ   / /!   ヽ    レ'/ ノ        >  ' ∠  -‐  ̄ノヽ   /
       {  i l    !    /  フ       /     -‐ / ̄/〉 〈 \ /!

なんて言われるのでは・・・?

なのでここは一段進歩させ、Javascriptで動的にテキストボックスを増減させることを考えてみましょう。
DOMを操作するため、テーブルにIDを振ります。


<table border="1" id="tbl" >
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input type="text" name="input" value="1" /></td></tr>
<tr><td>2</td><td><input type="text" name="input" value="2" /></td></tr>
<input type="submit" name="add" value="+" /> <input type="submit" name="sub" value="-" />
<input type="submit" value="登録" />
</table>

Javasciptでテーブルの行を追加するにはinsertRow()メソッドを、削除するにはdeleteRow()メソッドを使用します。
今回の場合は「+」ボタンで追加、「-」ボタンで削除するので、それぞれのボタンのonClick属性に追加、削除のアクションを追加します。


<input name="add" value="+" type="submit" onclick="addRow()"><input name="sub" value="-" type="submit" onclick="delRow()">

それぞれaddRow()、delRow()が追加、削除ボタンを押したときに呼び出される関数です。


<script>
function addRow(){
var newRow = document.getElementById('tbl');
var i = newRow.rows.length;
var row = newRow.insertRow(i);
var newCell = row.insertCell(0);
newCell.innerHTML = i;
var newCell = row.insertCell(1);
newCell.innerHTML = '<input name="input" value="" type="text">';
}

function delRow(){
var delRow = document.getElementById('tbl');
var i = delRow.rows.length;
delRow.deleteRow(i-1);
}
</script>

全部合わせるとこうなる


<script>
function addRow(){
var newRow = document.getElementById('tbl');
var i = newRow.rows.length;
var row = newRow.insertRow(i);
var newCell = row.insertCell(0);
newCell.innerHTML = i;
var newCell = row.insertCell(1);
newCell.innerHTML = '<input name="input" value="" type="text">';
}

function delRow(){
var delRow = document.getElementById('tbl');
var i = delRow.rows.length;
delRow.deleteRow(i-1);
}
</script>
<table style="table-layout: auto;" border="1" id="tbl">
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input name="input" value="1" type="text"></td></tr>
<tr><td>2</td><td><input name="input" value="2" type="text"></td></tr>
</table>
<br><br><input name="add" value="+" type="submit" onclick="addRow()"><input name="sub" value="-" type="submit" onclick="delRow()"><br>
<input value="登録" type="button">

配列の下限チェックをしてないので、「-」を連打するとオブジェクトが全部消えちゃうけどその辺は割愛するとして、まあこれで一応に増減するフォームがDHTMLで出来ました。

こういうタイプのフォームが他にないのであれば、ひとまずこれで完成と言ってもいいと思いますが、動的にインプットを増減させるっていう需要って意外とあるもので、じゃあこいつを使い回せばいいじゃないと思ってみても

var row = newRow.insertRow(i);
var newCell = row.insertCell(0);
newCell.innerHTML = i;
var newCell = row.insertCell(1);
newCell.innerHTML = '<input name="input" value="" type="text">';

部分は、チェックボックスだったり、リストだったりその時々で変わることが多い。
のでもうすこし汎用的にできないものか考えてみる。

動的にTRオブジェクトを生成するわけではなく、必ず1コ前のTRをコピーするという仕様で考えた場合、JQueryにはcloneという大変素敵なメソッドがあるので、それを使えば超楽に出来きますね。

とりあえずJQueryを使うようにソースを修正

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<table style="table-layout: auto;" border="1" id="tbl">
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input name="input" value="1" type="text"></td></tr>
<tr><td>2</td><td><input name="input
" value="2" type="text"></td></tr>
</table>
<br><br><input name="add" class="add" value="+" type="button"><input name="sub" class="del" value="-" type="button"><br>
<input value="登録" type="button">

先頭でGoogleにホストされてるJQueryを呼び出すように1行追加し、「+」「-」が余計なポストしないようにtypeをボタンに変えます。
操作するテーブルを特定するためにテーブルにIDを指定し、ボタンを押したら追加、削除するアクションのためにボタンにもCLASSを追加しておきます。

スクリプト部を作成

$().ready(function(){
$(".add").click(function(){
var n = document.getElementById("tbl");
var nowRow = n.rows.length;
var cloned = $("#tbl tr:nth-child("+nowRow+")");
afRow = nowRow + 1;
$(cloned).clone(true).insertAfter(cloned);
$("#tbl tr:nth-child("+afRow+") input").val("");
$("#tbl tr:nth-child("+afRow+") td:nth-child(1)").text(nowRow);
});

$(".del").click(function(){
var n = document.getElementById("tbl");
var m = n.rows.length;
if (m <= 2) {
return;
}
n.deleteRow(m-1);
});
});

$().readyは説明不要として(DOMの準備ができたら実行の意)、

$(".add").clickで「+」ボタンが押されたら発生するアクションを記述します。
最初の2行でテーブルの行数を数えます。
nowRowに入るのは末尾の行なので、clonedに末尾の行のJQueryオブジェクトを格納します。

$(cloned).clone(true).insertAfter(cloned);

で末尾のTRオブジェクトの後ろに複製したTRオブジェクトを追加してます。
このときのtrueが結構大事で、これがついてると既存のイベントもコピーできます。
最後の2行は連番と追加したINPUTのクリアを行ってます。

$(".del").clickはクリックされたらTRを削除するイベントです。
余計に消さないようにIF文が入ってます。

全部合わせたのがこちら

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script>
$().ready(function(){
$(".add").click(function(){
var n = document.getElementById("tbl");
var nowRow = n.rows.length;
var cloned = $("#tbl tr:nth-child("+nowRow+")");
afRow = nowRow + 1;
$(cloned).clone(true).insertAfter(cloned);
$("#tbl tr:nth-child("+afRow+") input").val("");
$("#tbl tr:nth-child("+afRow+") td:nth-child(1)").text(nowRow);
});

$(".del").click(function(){
var n = document.getElementById("tbl");
var m = n.rows.length;
if (m <= 2) {
return;
}
n.deleteRow(m-1);
});
});
</script>
<table style="table-layout: auto;" border="1" id="tbl">
<tr><td>No.</td><td>入力値</td></tr>
<tr><td>1</td><td><input name="input" value="1" type="text"></td></tr>
<tr><td>2</td><td><input name="input
" value="2" type="text"></td></tr>
</table>
<br><br><input name="add" class="add" value="+" type="button"><input name="sub" class="del" value="-" type="button"><br>
<input value="登録" type="button">

さらにこれをプラグイン化したらどこでも呼び出せて便利なんだけど、時間の関係で今日はここまで。
プラグイン化はまた後日〜。