develpr
develpr

Reputation: 1406

How to use Laravel Livewire with Eloquent Models?

I am in the process of trying out Laravel Livewire with a project for the first time. I am trying to build a fairly simple form with one set of cascading dropdowns - one input dependent on the other. But, when I try to pass an eloquent object to a component property, it is converted to a string so I can not access any of the object's properties.

I feel like there is something very simple I may be missing.

Here is my component code:

PostComponent.php

class PostComponent extends Component
{
    public $manufacturers;
    public $manufacturer = 'Select a Manufacturer';
    public $cars;

    public function mount()
    {
        $this->manufacturers = Manufacturer::orderBy('name')->get(); 
    }
    
    public function updated()
    {
        $this->cars = Car::where('manufacturer_id', $this->manufacturer->id)->get();
    }

    public function render()
    {
        return view('livewire.post-component');
    }

Here is my blade file:

<label for="manufacturer">Manufacturer</label>
<select wire:model="manufacturer" id="manufacturer">
    <option selected="selected" disabled>Select a Manufacturer</option>
        @foreach($manufacturers as $selectableManufacturer)
            <option value="{{ $selectableManufacturer }}">{{ $selectableManufacturer->name }}</option>
        @endforeach
</select>

When I attempt to select a manufacturer in the dropdown, I can log the $manufacturer and see that the value is

{"id":16,"name":"Manufacturer1","description":"lorem ipsum","created_at":"2020-06-26T23:44:37.000000Z","updated_at":"2020-06-26T23:44:37.000000Z"}

But when I try to get the id of the manufacturer when attempting to select cars in the updated lifecycle hook, I get the error

Trying to get property 'id' of non-object

Any idea as to why this is happening and how to fix it?

Upvotes: 2

Views: 12228

Answers (3)

Salam El-Banna
Salam El-Banna

Reputation: 3870

Simply follow the documentation it is straight forward:

https://laravel-livewire.com/docs/2.x/properties#binding-models

Upvotes: -1

Fawzan
Fawzan

Reputation: 4849

You should sync the id of the selected manufacturer and use that in an updated hook. Here is how you can do it.

class PostComponent extends Component
{
    public $manufacturers;
    public $manufacturer_id;
    public $manufacturer = 'Select a Manufacturer';
    public $cars;

    public function mount()
    {
        $this->manufacturers = Manufacturer::orderBy('name')->get(); 
    }
    
    public function updatedManufacturerId()
    {
        $this->cars = Car::where('manufacturer_id', $this->manufacturer_id)->get();
    }

    public function render()
    {
        return view('livewire.post-component');
    }
}

The frontend can remain same.

    <label for="manufacturer_id">Manufacturer</label>
    <select wire:model="manufacturer_id" id="manufacturer_id">
        <option selected="selected" disabled>Select a Manufacturer</option>
        @foreach($manufacturers as $selectableManufacturer)
        <option value="{{ $selectableManufacturer->id }}">{{ $selectableManufacturer->name }}</option>
        @endforeach
    </select>

Upvotes: 1

Irfan
Irfan

Reputation: 1030

The issue with your implementation is that, in the select box what you echo out in the blade is a string, not an object, so wire modal will do its job by getting the value of the input event and sync it with the backend. There are two ways that you can achieve your goal.

  1. Give the value of the select option as the manufacturer id, then you can directly use it in the updated lifecycle hook.

 <label for="manufacturer_id">Manufacturer</label>
    <select wire:model="manufacturer_id" id="manufacturer_id">
        <option selected="selected" disabled>Select a Manufacturer</option>
        @foreach($manufacturers as $selectableManufacturer)
        <option value="{{ $selectableManufacturer->id }}">{{ $selectableManufacturer->name }}</option>
        @endforeach
    </select>

In the updated hook,

 
 public $manufacturer_id; 
 public function updated() 
    {
        $this->cars = Car::where('manufacturer_id', $this->manufacturer_id)->get();
    }

  1. Or just use the json_decode() function to make it an object and then access the id property as you have done.

 public function updated()
    {
        $manufacturer = json_decode($this->manufacturer);
        $this->cars = Car::where('manufacturer_id', $manufacturer->id)->get();
    }

But the healthy approach would be to use the id as the value.

Upvotes: 2

Related Questions