formで同じname属性のvalueがうまく取れない

プログラミング

formで同じname属性をループして違うvalueを設定し、いざvalueを取得しようと思っても思い通りの結果にならないことがある?

例えば、よくある何かのマスター(商品マスターなど)をforeachで回してマスターの各レコードをtableとして表示し、各行に対して「削除」が行うことを想定しましょう。

問題のあるコード

下記の「削除」ボタンを押すとどうなるでしょうか?狙った行のレコードが削除されるでしょうか?

<form action="/delete_product_mst/" method="post">
<table border="1">
    <tr>
        <th>商品名</th>
        <th>価格</th>
        <th>重量</th>
        <th>削除</th>
    </tr>
@foreach ($product_mst_list as $product)
    <tr>
        <td><input type="hidden" name="productMstId" value="{{$product['productMstId']}}">{{$product['productMstId']}} : {{$product['name']}}</td>
        <td>{{$product['price']}}</td>
        <td>{{$product['weight']}}</td>
        <td><button type="submit">削除</button></td>
    </tr>
@endforeach
</table>
</form>

答えはNO!です。

何故でしょうか?ブラウザの「ページのソースを表示」で見てみても、ちゃんと各行の<input type=”hidden” name=”productMstId” value={{$product[‘productMstId’]}}>が挿入されていたにも関わらず、「削除」を押しても狙った行ではなく、違う行のレコードが削除されてしまうことになります。

理由はnameがすべて同じだからです。nameが同じだと、submitで送信した時に「どのname」のvalueを対象に処理していいか分からないので思ったのと違った結果になってしまうのですね。

解決方法その1、そもそも違うnameにしてしまえ

nameが同じだとどのnameなのかが分からないなら、ループ毎に違うnameを与えてやればいいですね。ただ、この方法だと受信側(phpなど)でも、name毎の処理になってしまうので、とてもじゃないがやってられないのでボツ。

解決方法その2、button毎にformタグをつけろ

例のコードだと、一番外側に<form>タグをかましていますよね。submitを押した時に同じnameが複数個あると正しく処理できないのです。

ループで<button>の生成毎にformタグも一緒に生成すれば、そのボタン専属のformになるわけなのでnameが同じでもかぶらなくなります。

<table border="1">
    <tr>
        <th>商品名</th>
        <th>価格</th>
        <th>重量</th>
        <th>削除</th>
    </tr>
@foreach ($product_mst_list as $product)
    <tr>
        <td>{{$product['productMstId']}} : {{$product['name']}}</td>
        <td>{{$product['price']}}</td>
        <td>{{$product['weight']}}</td>
        <form action="/delete_product_mst/" method="post">
            <input type="hidden" name="productMstId" value="{{$product['productMstId']}}">
            <td><button type="submit">削除</button></td>
        </form>
    </tr>
@endforeach
</table>

解決方法その3、submitされる前に送信データを書き換えろ

そもそもだが、<input type=”hidden” name=”productMstId” value={{$product[‘productMstId’]}}>をループで設定する必要がなく、<form>タグの中で一つだけ設定してsubmitの時にそのvalueを書き換えてやればいいです。

<form action="/delete_product_mst/" method="post">
<input type="hidden" id="productMstId" name="productMstId" value="">
<table border="1">
    <tr>
        <th>商品名</th>
        <th>価格</th>
        <th>重量</th>
        <th>削除</th>
    </tr>
@foreach ($product_mst_list as $product)
    <tr>
        <td>{{$product['productMstId']}} : {{$product['name']}}</td>
        <td>{{$product['price']}}</td>
        <td>{{$product['weight']}}</td>
        <td><button type="button" class="deleteButton">削除</button></td>
    </tr>
@endforeach
</table>
</form>

<script>
    // jQueryで削除ボタンを押した後、productMstIdを設定してからsubmit
    $(".deleteButton").("click", function(){
        var rowData = $(this).closest('tr').children("td");
        var productMstId = rowData[0];
        productMstId = $.trim(productMstId.split(":")[0]);
        $("#productMstId").val(productMstId);
        $("form").submit();
    });
</script>

jQuery、Javascript、CSS書籍紹介

コメント

タイトルとURLをコピーしました