Giles Bennett
Giles Bennett

Reputation: 1636

Livewire generating a collection on mount, but an array on refresh

I have a (relatively) simple Livewire controller which, on mount() generates a collection of games, grouped by their start dates, and assigns it to the $games public property.

public $games;
protected $rules = [];
...
public function mount() {
    $now = Carbon::now();
    $games = Game::where('start', '>', $now)->orderBy('start', 'ASC')->get();
    $games = $games->groupBy(function($item) {
        return $item->start->format("Y-m-d H:i:s");
    })->collect();
    $this->games = $games;
}

The corresponding component then loops through the dates, outputs the date, and then sends the games themselves to a Blade component (irrelevant styling removed):

@foreach($games as $date => $thegames)
    <div>
        {{ \Carbon\Carbon::createFromFormat("Y-m-d H:i:s", $date)->format("l jS \of F Y - g:i A") }}
    </div>
    <div>
        <x-individual.game :allgames="$thegames" :user="Auth::user()"></x-individual.game>
    </div>
@endforeach

The Blade component then loops through the games that it's been given and renders each of them (simplified below) :

@foreach($allgames as $game)
    <div>
        <div>
            <h3>
            {{ $game->game->name }}
            </h3>
        </div>
    </div>
@endforeach

Within that component (not shown) are wire:click buttons which may add a person to the game, or remove them. That, in turn, fires the refresh() function of the original Livewire component, which is identical to the mount() function save that it emits the refreshComponent event at the end :

public function refreshThis() {
    $now = Carbon::now();
    $games = Game::where('start', '>', $now)->get();
    $games = $games->groupBy(function($item) {
        return $item->start->format("Y-m-d");
    })->collect();
    $this->games = $games;
    $this->emit('refreshComponent');
}

That's where the problem starts. Rather than re-render the component, as it should, it generates an error of "Attempt to read property "game" on array" within the blade component :

{{ $game->game->name }}

and sure enough, at that point, $game is now an array, not an Eloquent object (or whatever it was first time around).

If I manually refresh the page, the changes are shown without issue. But why is it issuing me an array on refreshing, and (more importantly) how can I stop it?

Upvotes: 1

Views: 1236

Answers (1)

Ray C
Ray C

Reputation: 310

You could add the $games to the render method instead and it will refresh the data:

public function render()
{
    $now = Carbon::now();
    $games = Game::where('start', '>', $now)->orderBy('start', 'ASC')->get();
    $games = $games->groupBy(function($item) {
        return $item->start->format("Y-m-d H:i:s");
    })->collect();

    return view('livewire.your_component_view', [
        'games' => $games
    ]);
}

Then refresh the component (in your main component):

public function refreshThis() {
    $this->render();
}

If you are calling refresh from a child component you can call it form there: Child component:

$this->emit('refreshThis');

Upvotes: 2

Related Questions