Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

stevegoddard14's avatar

Livewire3 Nested Data Binding

I'm migrating an app from Livewire2 to Livewire3.

Livewire2 supported nested data binding. Very brief docs here: https://laravel-livewire.com/docs/2.x/data-binding#nested-binding

This meant that you cold feed a model into a component and then access and update all the model attributes without having to explicitly bind and declare each attribute.

So for instance, you could call a component:

@livewire('invoices.invoice-customer-details', ['invoice' => $invoice])

And then in the component just declare the model (and validation rules):

namespace App\Livewire\Invoices;

use Livewire\Component;

class InvoiceCustomerDetails extends Component
{
    public $invoice;

    //Validation rules.
    protected $rules = [
        'invoice.customer_ref' => 'nullable|min:1|max:100',
        'invoice.date' => 'required|date_format:Y-m-d\TH:i:s', //'Date' field sends this format.
    ];

    public function render()
    {
        return view('livewire.invoices.invoice-customer-details');
    }
}

Then finally in the view you could wire:model to any of the attributes (provided you had declared a validation rule):

<div>

  <form wire:submit="submitForm" autocomplete="off">

    <div class="row">
      <div class="col-md-12 mt-1">
                
        <div class="row mb-2">
          <label for="CustomerRef" class="col-sm-4 col-form-label col-form-label-sm">Customer Ref</label>
          <div class="col-sm-8">
            <input wire:model.live.debounce.500ms="invoice.customer_ref" type="text" name="invoice.customer_ref" class="form-control form-control-sm @error('invoice.customer_ref') is-invalid @enderror" id="CustomerRef" placeholder="Customer reference" autofocus>
            @error('invoice.customer_ref')
              <div class="invalid-feedback">
                {{ $message }}
              </div>
            @enderror
          </div>
        </div>

        <div class="row mb-2">
          <label for="Date" class="col-sm-4 col-form-label col-form-label-sm">Date</label>
          <div class="col-sm-8">
            <input wire:model.live.debounce.500ms="invoice.date" type="datetime-local" name="invoice.date" class="form-control form-control-sm @error('invoice.date') is-invalid @enderror" id="Date" placeholder="dd/mm/yyyy H:i" @cannot('administer') disabled @endcannot>
            @error('invoice.date')
              <div class="invalid-feedback">
                {{ $message }}
              </div>
            @enderror
          </div>
        </div>


        <button type="submit" class="btn btn-sm btn-primary text-white float-end"><i class="fas fa-save me-1"></i> Save</button>

      </div>
    </div>

  </form>

</div>

Suffice to say, I can't get this working in Livewire 3 and I cannot find any documentation about it. It all starts working if I declare each attribute, and then add each attribute to the mouth method (or use the new fill function to mount them all).

Anyone having the same issue or able to advise on why they isn't working for me in Livewire3?

Thanks, Steve

0 likes
5 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

In Livewire 3, nested data binding is no longer supported. You will need to explicitly bind and declare each attribute in your component.

To update your code to work with Livewire 3, you will need to make the following changes:

  1. Remove the $invoice property from your component and declare each attribute individually.
namespace App\Livewire\Invoices;

use Livewire\Component;

class InvoiceCustomerDetails extends Component
{
    public $customer_ref;
    public $date;

    //Validation rules.
    protected $rules = [
        'customer_ref' => 'nullable|min:1|max:100',
        'date' => 'required|date_format:Y-m-d\TH:i:s',
    ];

    public function render()
    {
        return view('livewire.invoices.invoice-customer-details');
    }
}
  1. Update your view to use the new attribute names.
<div>
  <form wire:submit="submitForm" autocomplete="off">
    <div class="row">
      <div class="col-md-12 mt-1">
        <div class="row mb-2">
          <label for="CustomerRef" class="col-sm-4 col-form-label col-form-label-sm">Customer Ref</label>
          <div class="col-sm-8">
            <input wire:model.debounce.500ms="customer_ref" type="text" name="customer_ref" class="form-control form-control-sm @error('customer_ref') is-invalid @enderror" id="CustomerRef" placeholder="Customer reference" autofocus>
            @error('customer_ref')
              <div class="invalid-feedback">
                {{ $message }}
              </div>
            @enderror
          </div>
        </div>

        <div class="row mb-2">
          <label for="Date" class="col-sm-4 col-form-label col-form-label-sm">Date</label>
          <div class="col-sm-8">
            <input wire:model.debounce.500ms="date" type="datetime-local" name="date" class="form-control form-control-sm @error('date') is-invalid @enderror" id="Date" placeholder="dd/mm/yyyy H:i" @cannot('administer') disabled @endcannot>
            @error('date')
              <div class="invalid-feedback">
                {{ $message }}
              </div>
            @enderror
          </div>
        </div>

        <button type="submit" class="btn btn-sm btn-primary text-white float-end"><i class="fas fa-save me-1"></i> Save</button>
      </div>
    </div>
  </form>
</div>

By making these changes, your component should work as expected in Livewire 3.

stevegoddard14's avatar

@LaryAI Thanks. But that really sucks. I'm going to have to fix a lot of livewire components...

RogierW's avatar

Model binding is no longer supported by default in Livewire v3. However, you can enable it in the config/livewire.php file:

'legacy_model_binding' => true,

4 likes
gtdab's avatar

@RogierW I know this is an old thread, but the legacy_model_binding setting doesn't seem to work for me. Any time i bind a field to a nested model e.g. wire:model="selected.first_name" I get an error in the console stating "Cannot read properties of null (reading 'first_name')" when the component loads.

kbush's avatar

@gtdab A fellow co-worker just ran into this issue today when upgrading an app from livewire 2 to 3 and I can confirm legacy_model_binding does still work. Thought you (and maybe others) might want to know.

Please or to participate in this conversation.