解説コードを読んでみよう
このサンプルでわかること
- jQuery で表(table)に1行ずつ入力欄を追加する方法
name="text_1[]"のように[]を付けると、PHP で配列として受け取れること- 受け取った配列を
foreachで1行ずつ取り出す方法
使っているファイル
- index.php入力フォームと「行追加」の JavaScript
- data.php送信された値を受け取って表示する PHP
1. 入力フォームを作る
入力欄は表(table)の中に並べます。行を追加する場所は <tbody> の中です。ボタンは <tfoot> に置いて、行が増えても常に表のいちばん下に来るようにしています。
<form action="data.php" method="post">
<table class="add-form">
<thead>
<tr>
<th>材料</th>
<th>数量</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="text_1[]" placeholder="例:たまご"></td>
<td><input type="text" name="text_2[]" placeholder="例:2個"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="2"><button id="add" class="btn btn-default" type="button">+ 行追加</button></td>
</tr>
</tfoot>
</table>
<hr>
<input type="submit" class="btn btn-default" name="send" value="送信">
</form>
注目してほしいのは入力欄の名前です。name="text_1[]" のように、名前の最後に [] を付けています。
同じ名前の入力欄がいくつもあると、普通は最後の1つの値しか PHP に届きません。名前に [] を付けておくと、PHP は同じ名前の値を全部まとめて配列で受け取ってくれます。入力欄の数が決まっていない「行追加」フォームでは、この書き方が欠かせません。
2. 「行追加」ボタンで1行増やす(jQuery)
<script>
$(function() {
// 「行追加」ボタンが押されたら、1行分の HTML を表の最後に追加する
$('button#add').click(function(){
var tr_row = '' +
'<tr>' +
'<td><input type="text" name="text_1[]"></td>' +
'<td><input type="text" name="text_2[]"></td>' +
'</tr>';
$(tr_row).appendTo($('.add-form > tbody'));
});
});
</script>
$('button#add').click(function(){ ... })… 「行追加」ボタン(id="add")がクリックされたら、中の処理を実行します。var tr_row = '<tr>...</tr>'… 追加する1行分の HTML を文字列として作ります。最初の行と同じnameにするのがポイントです。$(tr_row).appendTo($('.add-form > tbody'))… 文字列を HTML の部品に変えて、class="add-form"の表のtbodyの最後に追加します。
追加先を $('table > tbody') のように書くと、ページ内のすべての表に行が追加されてしまいます。class="add-form" のような目印を付けて、追加先の表を1つに絞りましょう。
ボタンには必ず type="button" を付けます。<form> の中にある <button> は、何も書かないと「送信ボタン」として扱われ、押した瞬間にフォームが送信されてしまいます。
3. PHP で配列として受け取る
送信先の data.php では、$_POST['text_1'] が配列になっています。たとえば2行入力して送信すると、中身は次のようになります。
Array
(
[text_1] => Array
(
[0] => たまご
[1] => 牛乳
)
[text_2] => Array
(
[0] => 2個
[1] => 200ml
)
[send] => 送信
)
同じ行の「材料」と「数量」は、同じ番号(添字)に入ります。そこで、text_1 を foreach で1つずつ取り出し、同じ番号の text_2 と組み合わせて表にしています。
// 受け取った値(送信されていなければ空の配列にする)
$text_1 = (array)($_POST['text_1'] ?? []);
$text_2 = (array)($_POST['text_2'] ?? []);
<table class="table table-striped">
<tr><th>添字 [i]</th><th>$_POST['text_1'][i](材料)</th><th>$_POST['text_2'][i](数量)</th></tr>
<?php foreach ($text_1 as $i => $value): ?>
<tr>
<td><?= h($i) ?></td>
<td><?= h($value) ?></td>
<td><?= h($text_2[$i] ?? '') ?></td>
</tr>
<?php endforeach; ?>
</table>
画面に表示するときは、必ず h()(中身は htmlspecialchars())を通しています。入力欄に <script> などを書かれても、ただの文字として表示されるので安全です。
PHP 8.3 で書き直したポイント
何も送信せずに data.php を直接開くと、$_POST['text_1'] は存在しません。古い書き方のままだと PHP 8 では警告が出るため、?? [](値がなければ空の配列を使う)で初期値を決めてから使うようにしました。
// 送信されていなければ空の配列にする
$text_1 = (array)($_POST['text_1'] ?? []);
3列目に「メモ」の入力欄(name="text_3[]")を追加してみましょう。最初の行と、JavaScript で追加する行の両方に書き足すのを忘れずに。data.php では $_POST['text_3'] で受け取れます。