0

I'm working with Laravel 11, Livewire 3.6.10, and Alpine.js (properly configured). I'm encountering an issue where wire:model doesn't bind the value to an input field after a page refresh, even though the variable is correctly set in the component.

What Works

  • Items are listed correctly in a table.
  • Adding a new item works perfectly.
  • Clicking "Edit" immediately after adding an item shows the form with values populated (including the input field).

The Issue

If I refresh the page and then click "Edit" on an item:

  • The variable {{ $name }} displays correctly.
  • But the input field bound with wire:model="name" does not show the value.

Code Snippets

<table class="min-w-full">
    <thead>
        <tr>
            <th>#NO</th>
            <th>Name</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
        @foreach ($list as $item)
            <tr>
                <td>{{ $loop->iteration }}</td>
                <td>{{ $item->name }}</td>
                <td>
                    <button wire:click="edit({{ $item->id }})">Edit</button>
                </td>
            </tr>
        @endforeach
    </tbody>
</table>

Edit Form

{{ $name }} <!-- Displays correctly -->

<form wire:submit.prevent="{{ $isEdit ? 'update' : 'store' }}">
    <input type="text" wire:model="name">
</form>

Edit method

public function edit($id)
{
    $inventory = ModelsInventory::findOrFail($id);

    $this->inventory_id = $id;
    $this->name = $inventory->name;
}

Debugging Summary

  • $name is correctly populated.
  • {{ $name }} displays the expected value.
  • However, <input wire:model="name"> does not reflect the value after a page refresh.

Question

Why is the value not binding to the input via wire:model after a page refresh, even though the component variable is correctly populated?

Note: the project is created with starter kit, laravel breeze, it has livewire and alpine configured.

app.js

import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'
import './bootstrap'; // assuming Livewire's stuff is here

// Only register Alpine once (before Livewire boots it)
window.Alpine = Alpine
Alpine.plugin(persist)

There are no browser console errors.

I have found a code snippet online that says as follow

Force DOM Update with Alpine

<input type="text" 
       wire:model="name" 
       x-data 
       x-init="$nextTick(() => { $el.value = '{{ $name }}' })">

I have tried this snippet, surprisingly it worked.

But the problem is that, I don't want these extra things in my input field, I want to use only wire:model="name" and it should work.

2
  • Please explain further: is the form placed in the same view as the list or is it in a standalone view? However I think that the Alpine snippet is not necessary and even less so @entangle. In any case you need to add a wire:key with a unique key to each <tr> in the table. Note that in the form you are calling update or store while in the class you have an edit() method that also requires a $id Commented Apr 29 at 14:00
  • The form is in the same view, and the issue was related to alpine (multiple instances running). Thanks for the suggestions. Commented Apr 30 at 5:05

4 Answers 4

2

Since you're using Livewire 3.6.10, Laravel 11, and Alpine.js (which is already configured), the best solution to ensure proper two-way binding after page refresh is:

Use Alpine's @entangle to Bridge Livewire and DOM

Replace this:

<input type="text" wire:model="name">

With this:

<input type="text" x-data x-model="@entangle('name')">

Working Example:

<form wire:submit.prevent="{{ $isEdit ? 'update' : 'store' }}">
    <input type="text" x-data x-model="@entangle('name')" class="border rounded p-1">
</form>
Sign up to request clarification or add additional context in comments.

1 Comment

The input field shows [object Object]
0

In your edit function

public function edit($id)
{
    # ....
    $this->dispatch('refreshInput'); # add this
}

In Blade, wrap your form input inside a div key

<div wire:key="{{ $inventory_id }}">
    <form wire:submit.prevent="{{ $isEdit ? 'update' : 'store' }}">
        <input type="text" wire:model="name">
    </form>
</div>

Or should work with server-side value

<input
  type="text" wire:model="name"
  value="{{ $name }}" />

Comments

0

Your Alpine.js setup might not be properly processing Livewire's @entangle. Install the official

Install the package:

npm install @livewire/livewire-alpine

Update app.js:

import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'
import LivewireAlpinePlugin from '@livewire/livewire-alpine'
window.Alpine = Alpine
Alpine.plugin(persist)
Alpine.plugin(LivewireAlpinePlugin) // Add this line
Alpine.start()

Now use $wire.entangle() in your input:

<input 
    type="text" 
    x-data 
    x-model="$wire.entangle('name')" 
    class="border rounded p-1"
>

Comments

0

Problem

While debugging, I noticed the following warning in the browser console:

livewire.js?id=df3a17f2:10202 Detected multiple instances of Alpine running

This message suggested that Alpine.js was being loaded more than once, which causes conflicts in applications using Livewire.

Investigation

In Livewire v3.x, assets (JavaScript and CSS) are automatically injected into the <head> and <body> of pages containing Livewire components. This behavior is controlled via the inject_assets option in the config/livewire.php file:

'inject_assets' => true,

However, in my application, I was also manually initializing Alpine in resources/js/app.js like this:

import Alpine from 'alpinejs'
import persist from '@alpinejs/persist'

window.Alpine = Alpine // This line was causing the conflict
Alpine.plugin(persist)

This led to two Alpine instances being initialized—one by Livewire and one manually—which triggered the warning and broke expected behavior.

Solution

Latest Update on this issue

just commenting this line will fix the issue.

// window.Alpine = Alpine

Old method (not needed)

Here's what I did to fix it:

Commented out the line initializing the global Alpine instance in app.js:

// window.Alpine = Alpine

Updated the livewire.php config to prevent automatic asset injection:

'inject_assets' => false,

Manually added the Livewire assets in the Blade layout file:

@livewireStyles
@livewireScripts

Restarted the application to apply the changes. After doing this, everything worked smoothly—no more console warnings, and Livewire + Alpine behavior was as expected.

Note

I didn’t change anything in the model binding logic. The original binding remained untouched:

<form wire:submit.prevent="{{ $isEdit ? 'update' : 'store' }}">
    <input type="text" wire:model="name">
</form>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.