Alpine.js使用時のデータセットメモ

## はじめに
LaravelとAlpine.jsを組み合わせて使用する際、フロントの操作が楽になります。
しかしながらデータ処理をフロントで使用する場合、バックエンドからのデータをx-dataにセットする際、少し手間取ったのでメモります。

## データのセット
Alpine.jsで使用するデータをセットする際、のコンポーネントが初期化される前にセットする必要があります。

以下は、Alpine.jsの初期化前にデータを設定する方法を示した例です。
バックエンドからのデータをフロントで使えるようにセットします。

### Bladeテンプレート

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic Form</title>
    <script>
        // PHPでJavaScript変数を設定
        window.defaultRows = @json($defaultRows);
    </script>
    <script src="{{ asset('js/cdn.min.js') }}" defer></script>
</head>

<body>
    <h1>Dynamic Form</h1>

    @if (session('success'))
        <div style="color: green;">
            {{ session('success') }}
        </div>
    @endif

    {{-- デバッグ情報を表示 --}}
    <pre>{{ var_export($defaultRows, true) }}</pre>
    <pre id="debug"></pre>

    {{-- Alpine.jsのx-dataでJavaScript変数を使用 --}}
    <form x-data="{ rows: window.defaultRows }" x-init="console.log(rows)" method="POST" action="{{ route('form.submit') }}">
        @csrf
        <template x-for="(row, index) in rows" :key="index">
            <div>
                <label>
                    <span x-text="index + 1"></span> 番目のフィールド:
                    <input type="text" x-model="row.field" name="rows[][field]" />
                </label>
            </div>
        </template>
        <button type="button" @click.prevent="rows.push({ field: '' });">行の追加</button>
        <input type="submit" value="送信">
    </form>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            // デバッグ情報を表示
            document.getElementById('debug').textContent = JSON.stringify(window.defaultRows, null, 2);
        });
    </script>
</body>

</html>
```

### 説明
ポイントは以下になります。
1. **`<head>`内でJavaScript変数を設定**:
   - Alpine.jsのスクリプトを読み込む前に、バックエンドからのデータを`window.defaultRows`にセットします。
   `        window.defaultRows = @json($defaultRows);`
その際使用する@jsonディレクティブは、LaravelのBladeテンプレートエンジンの機能です。
このディレクティブは、PHPの配列やオブジェクトをJSON形式の文字列に変換し、そのままHTMLに出力するために使用されます。
例: @json($array)は、$arrayをJSONエンコードし、その結果をHTMLに出力します。

   - これにより、Alpine.jsのコンポーネントが初期化される前にデータが設定されます。

2. **`<script defer>`でAlpine.jsを読み込み**:
   - `defer`属性を使用して、HTMLの解析が完了するまでスクリプトの実行を遅らせます。ただし、先に設定した`window.defaultRows`はすでに利用可能です。

3. **`x-data`で`window.defaultRows`を使用**:
   - `x-data`ディレクティブ内で、`rows`に`window.defaultRows`を設定します。これにより、Alpine.jsが初期化されると同時にデータが設定されます。


## 終わりに
x-dataに@json($変数)をセットできないのが少々面倒でした。
bladeで正しくエスケープ処理がされず、処理するには現状工夫が必要そうです。



## その他
以下今回使用したソースを記載します

```web.php
<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;
use App\Http\Controllers\FormController;

Route::get('/form', [FormController::class, 'showForm'])->name('form.show');
Route::post('/form', [FormController::class, 'submitForm'])->name('form.submit');
```

```FormController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FormController extends Controller
{
    public function showForm()
    {
        // デフォルトの行データを設定
        $defaultRows = [
            ['field' => 'default value 1'],
            ['field' => 'default value 2'],
        ];

        return view('form', compact('defaultRows'));
    }

    public function submitForm(Request $request)
    {
        // フォームのデータを処理します。ここではデータのバリデーションと保存などを行います。
        $validatedData = $request->validate([
            'rows' => 'required|array',
            'rows.*.field' => 'required|string|max:255',
        ]);

        // データの処理例
        foreach ($validatedData['rows'] as $row) {
            // 各行のデータを処理します。
            // 例: DBに保存するなど
        }

        return redirect()->route('form.show')->with('success', 'データが送信されました。');
    }
}

```

## 参考

https://tech.yappli.io/entry/alpinejs