初めてのfetch（JSでの非同期通信・配列を送る）

PHPファイルの文字コードが "Shift JIS" の環境で作成していました。


```php
<?php
//〜PHPの処理色々省略〜
?>
 <!-- HTMLの記載色々省略 -->

<form method="post">
    <div id="main">
        <div id="search_item_box">
            <div id="search_item_num_0" data-num="0">
                商品カテゴリ選択：
                <!-- name="item_cate[]"とすることで配列入力を配列型にすることができる -->
                <label><input type="radio" name="item_cate[0]" value="none" checked>なし</label >
                <label><input type="radio" name="item_cate[0]" value="product">食材</label >
                <label><input type="radio" name="item_cate[0]" value="product_tokubai">特売（食材）</label >
                <label><input type="radio" name="item_cate[0]" value="product_b">食材以外</label >
                <label><input type="radio" name="item_cate[0]" value="product_b_tokubai">特売（食材以外）</label >
                <label><input type="radio" name="item_cate[0]" value="product_new">新登録商品（食材）</label >
                <label><input type="radio" name="item_cate[0]" value="product_b_new">新登録商品（食材以外）</label >
                <div>
                    品番シリアル：
                    <input type="text" name="dat_serial[0]" value="">
                    <button type="button" onclick="item_remove('search_item_num_0')"><i class="fas fa-times"></i></button>
                </div>
            </div>
        </div>

        <div>
            <button type="button" onclick="asynchronous_btn(this.form, 'search')">非同期検索</button>
            <!-- このボタンを押すと非同期通信が発生 -->

            <button type="button" onclick="item_addition()"><i class="fas fa-plus"></i></button>
            <!-- このボタンを押すと入力欄が増える -->
        </div>

        <div id="search_item_display">
            <!-- ここに検索結果が表示される -->
        </div>
    </div>

</form>




<script>

 // 商品検索欄追加
            let searchNum = 0;
            function item_addition(){
                searchNum++;

                let searchItem = `<div id="search_item_num_${searchNum}" data-num="${searchNum}">
                                    商品カテゴリ選択：
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="none" checked>なし</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product">食材</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_tokubai">特売（食材）</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_r">ロイヤルキッチン</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_b">食材以外</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_b_tokubai">特売（食材以外）</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_gift">ギフト食材</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_new">新登録商品（食材）</label >
                                    <label><input type="radio" name="item_cate[${searchNum}]" value="product_b_new">新登録商品（食材以外）</label >
                                    <div>
                                        品番シリアル：
                                        <input type="text" name="dat_serial[${searchNum}]" class="to_check" value="">
                                        <button type="button" onclick="item_remove('search_item_num_${searchNum}')"><i class="fas fa-times"></i></button>
                                    </div>

                                </div>`;

                const target = document.getElementById('search_item_box');

                target.insertAdjacentHTML('beforeend', searchItem);
            }


            // 商品検索欄削除
            function item_remove(searchItemNum){
                const removeTarget = document.getElementById(`${searchItemNum}`);
                removeTarget.remove();
            }



// 非同期検索
function asynchronous_btn(form) {
    let displayTarget = '';
    let item_cate_arr=[];
    let dat_serial_arr=[];

    let searchItems = document.getElementById('search_item_box');
    // search_item_boxのidの要素を取得
    let itemSearchCount = searchItems.childElementCount;
    // searchItemsの子要素の数を数える
    

    // formの配列をJSの配列に転換
    for (let i = 0; i < itemSearchCount; i++) {
        let searchItemDataset = searchItems.children[i].dataset.num;
        // searchItemsのi番目の子要素のデータ属性の値を取得

        item_cate_arr.push(form.elements[`item_cate[${searchItemDataset}]`].value)
        // formのname属性がitem_cate[]の値を一つずつ取り出し、JSの配列に入れる
      
        dat_serial_arr.push(form.elements[`dat_serial[${searchItemDataset}]`].value)
        // formのname属性がdat_serial[]の値を一つずつ取り出し、JSの配列に入れる
    }


    // 送信処理
    fetch('./asynchronous_search.php',{// 送信先
        method:'POST',// 送信メソッド
        body: new URLSearchParams({// 送信する値
            item_cate : JSON.stringify(item_cate_arr),
            dat_serial : JSON.stringify(dat_serial_arr),
            // JSON.stringify()でJSON形式にエンコードすることで、「文字列化」して送信できるようにする
        })
    })// ここでasynchronous_search.phpに送信される


    // asynchronous_search.phpから結果が返ってくる
    .then(response => response.json())//JSON形式できちんと返ってきているかの確認（値は.thenの引数に入る）

    .then(data => {//成功時の処理（値は.thenの引数に入る）
        displayTarget = document.getElementById('search_item_display');

        displayTarget.innerHTML = data;
        // displayTargetの子要素として返ってきた値を設置（HTML形式で返すようにしている）
    })

    .catch(error => {
        // ネットワークエラーでも !response.ok でもここで処理できる
        console.error('エラーが発生しました', error);
    });

}
</script>
```

```asynchronous_search.php
<?php
//送信された値を受け取る
$p_item_cate_arr = '';
isset($_POST['item_cate']) && $p_item_cate_arr = json_decode($_POST['item_cate']);

$p_dat_serial_arr = '';
isset($_POST['dat_serial']) && $p_dat_serial_arr = json_decode($_POST['dat_serial']);

//////////////////////////////////////////////////////////////////////
// $search_result = DBから該当のデータを取得（省略）
//////////////////////////////////////////////////////////////////////


//商品検索結果表示
$search_result_disp = '';
if($search_result){
    if(empty($search_result)){
        $search_result_disp .= '<p><font color="red">対象商品が見つかりません。</font></p>';
    }else{
        $search_result_disp .= '<table border="1" style="border-collapse: collapse">
                                    <tr>
                                        <th>品番</th>
                                        <th>商品名</th>
                                        <th>単価</th>
                                    </tr>
                                ';
        foreach($search_result as $item_dat){
            $search_result_disp .= sprintf('<tr>
                                                <td>%1$s</td>
                                                <td>%2$s</td>
                                                <td>%3$s円</td>
                                            </tr>
                                            '
                                        ,$item_dat['dat_serial']
                                        ,$item_dat['dat_item']
                                        ,number_format($item_dat['unit_price'])
            );
        }
        $search_result_disp .= '</table>';
    }
}

mb_convert_variables("utf-8","sjis",$search_result_disp);
//文字コードをsjisからutf-8にエンコード
header('Content-Type: application/json; charset=utf-8');
//送り返すデータのタイプを宣言・文字コードも宣言
echo json_encode($search_result_disp);
//JSON型にエンコードして送り返す
//（PHPのjson_encodeでは文字コードがutf-8になるらしい。その為先にutf-8に変換しておかないとエラーになる）


exit;
// 処理を切る為

```