Laravelのとあるプロジェクトで、Livewireを使用したリアルタイムバリデーションを実装していた時にハマったことの備忘録。

マイページの会員情報変更ページで市区町村selectに、会員データの初期値を持たせるため以下のようなBladeファイルを用意した。

<select name="city_cd" wire:ignore id="city_cd" class="form-select @error('city_cd') is-invalid @enderror">
    <option value="">選択してください</option>
    @foreach ($citys as $city)
        <option value="{{ $city->id }}"{{ (old('city_cd') && old('city_cd') == $city->id) || ($customer->city_cd == $city->id) ? 'selected' : '' }}>{{ $city->name }}</option>
    @endforeach
</select>

$citysはコントローラー側で取得してきた市区町村データのidとnameをプロパティとして持つオブジェクトを複数持つ配列だ。

<input id="name01" type="text" wire:model.lazy="name01" class="form-control @error('name01') is-invalid @enderror" name="name01" required>

そして同じフォーム内には氏名など、上記のようなLivewireのリアルタイムバリデーションを適用したinput要素も存在するのだが、これらの項目に対し値の変更を行うと以下のエラーが発生してしまう。
今回はこの問題について、解決に至った方法を紹介する。

Attempt to read property “id” on array

エラーの内容

先述のエラーを直訳すると「配列のプロパティidを読み取ろうとしている」とのことで、なぜかオブジェクトであるはずの$cityが配列と認識され、プロパティidにアクセスできなくなってしまっているようだ。

解決に至った方法

どうやらLivewireのリアルタイムバリデーションが走った時点でオブジェクトが配列に変わってしまうようなので、<option>タグの出力の際に$cityのデータ型をif文で検証することにした。

完成したコードがこちら。

<select name="city_cd" wire:ignore id="city_cd" class="form-select @error('city_cd') is-invalid @enderror">
    <option value="">選択してください</option>
    @foreach ($citys as $city)
        @if (is_array($city))
            <option value="{{ $city['id'] }}"{{ (old('city_cd') && old('city_cd') == $city['id']) || ($customer->city_cd == $city['id']) ? 'selected' : '' }}>{{ $city['name'] }}</option>
        @else
            <option value="{{ $city->id }}"{{ (old('city_cd') && old('city_cd') == $city->id) || ($customer->city_cd == $city->id) ? 'selected' : '' }}>{{ $city->name }}</option>
        @endif
    @endforeach
</select>

これでオブジェクト、配列のどちらのデータ型にも対応できるようになり、無事この問題を解決することができた。