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

dmcconnell68's avatar

Livewire 3 Refresh when setting select values via javascript

Hi, I have a Livewire component that works as I expect it to when adding a new record. My issue is when a record needs to be edited. I load the values from the DB into the form, which has a dependent dropdown Livewire component with two selects. I can update the value of the first select, which works fine, but when I update the value of the second select, nothing happens. Any ideas on how I can get this to work as expected.

Component code:

<?php

namespace App\Livewire;

use Livewire\Component;
use App\Models\Application;
use App\Models\PermissionSet;

class ApplicationPermissionSetDropdown extends Component
{
    public $applications;
    public $permissionsets;
    public $selectedApplication = null;

    public function mount()
    {
        $this->applications = Application::all();
    }

    public function updatedSelectedApplication($application) {
        $this->permissionsets = PermissionSet::where('application_id', $application)->get();
    }

    public function render()
    {   
        return view('livewire.application-permission-set-dropdown');
    }
}

application-permission-set-dropdown.blade.php

<div class="form-row">
    <div class="col-lg-6 mb-4">
        <label class="form-label" for="application">Application</label>
        <select wire:model.live="selectedApplication" class="form-control" id="application" name="application" >
            <option value="">-- Select Application --</option>
            @foreach ($applications as $application )
                <option value="{{$application->id}}">{{$application->name}}</option>
            @endforeach

        </select>
        <span class="help-block">Select application for access group</span>
        <div class="invalid-feedback add-application-error">Incorrect!!</div>
    </div>

    @if (!is_null($application))
        <div class="col-lg-6 mb-4">
            <label class="form-label" for="permission_set">Permission Set</label>
            <select class="form-control" id="permission_set" name="permission_set">
                <option value="">-- Select Permission Set --</option>
                @if (!is_null($permissionsets))
                    @foreach ($permissionsets as $permissionset )
                        <option value="{{$permissionset->id}}">{{$permissionset->name}}</option>
                    @endforeach
                @endif
            </select>
            <span class="help-block">Select permission set that is to be applied to this access group</span>
            <div class="invalid-feedback add-permission-set-error"></div>
        </div>
    @endif
</div>

Javascript to update values

$('#application option[value="'+(x.input_data.application === null ? '' : x.input_data.application ) +'"]').attr("selected","selected");
$('#permission_set option[value="'+(x.input_data.permission_set === null ? '' : x.input_data.permission_set ) +'"]').attr("selected","selected");

Thanks for any assistance. David

0 likes
3 replies
LaryAI's avatar
Level 58

To address the issue of updating the second select element (Permission Set) when setting values via JavaScript in a Livewire component, you need to ensure that Livewire is aware of the changes made by JavaScript. Livewire components rely on their internal state to manage reactivity, and direct DOM manipulations via JavaScript won't automatically trigger Livewire updates.

Here's a step-by-step solution to ensure that the second select element updates correctly:

  1. Emit an Event from JavaScript to Livewire: When you update the select values via JavaScript, emit an event to notify Livewire of the change.

  2. Listen for the Event in the Livewire Component: Handle the event in the Livewire component to update its internal state.

  3. Update the Blade Template: Ensure the Blade template is correctly set up to reflect the changes.

Step 1: Emit an Event from JavaScript

Modify your JavaScript to emit an event to Livewire when the select values are updated:

$('#application').val(x.input_data.application).trigger('change');
$('#permission_set').val(x.input_data.permission_set).trigger('change');

// Emit events to Livewire
Livewire.emit('applicationUpdated', x.input_data.application);
Livewire.emit('permissionSetUpdated', x.input_data.permission_set);

Step 2: Listen for the Event in the Livewire Component

Update your Livewire component to listen for these events and update its state accordingly:

namespace App\Livewire;

use Livewire\Component;
use App\Models\Application;
use App\Models\PermissionSet;

class ApplicationPermissionSetDropdown extends Component
{
    public $applications;
    public $permissionsets;
    public $selectedApplication = null;
    public $selectedPermissionSet = null;

    protected $listeners = [
        'applicationUpdated' => 'setSelectedApplication',
        'permissionSetUpdated' => 'setSelectedPermissionSet'
    ];

    public function mount()
    {
        $this->applications = Application::all();
    }

    public function updatedSelectedApplication($application)
    {
        $this->permissionsets = PermissionSet::where('application_id', $application)->get();
    }

    public function setSelectedApplication($application)
    {
        $this->selectedApplication = $application;
        $this->updatedSelectedApplication($application);
    }

    public function setSelectedPermissionSet($permissionSet)
    {
        $this->selectedPermissionSet = $permissionSet;
    }

    public function render()
    {
        return view('livewire.application-permission-set-dropdown');
    }
}

Step 3: Update the Blade Template

Ensure the Blade template reflects the selected values correctly:

<div class="form-row">
    <div class="col-lg-6 mb-4">
        <label class="form-label" for="application">Application</label>
        <select wire:model.live="selectedApplication" class="form-control" id="application" name="application">
            <option value="">-- Select Application --</option>
            @foreach ($applications as $application)
                <option value="{{ $application->id }}">{{ $application->name }}</option>
            @endforeach
        </select>
        <span class="help-block">Select application for access group</span>
        <div class="invalid-feedback add-application-error">Incorrect!!</div>
    </div>

    @if (!is_null($selectedApplication))
        <div class="col-lg-6 mb-4">
            <label class="form-label" for="permission_set">Permission Set</label>
            <select wire:model.live="selectedPermissionSet" class="form-control" id="permission_set" name="permission_set">
                <option value="">-- Select Permission Set --</option>
                @if (!is_null($permissionsets))
                    @foreach ($permissionsets as $permissionset)
                        <option value="{{ $permissionset->id }}">{{ $permissionset->name }}</option>
                    @endforeach
                @endif
            </select>
            <span class="help-block">Select permission set that is to be applied to this access group</span>
            <div class="invalid-feedback add-permission-set-error"></div>
        </div>
    @endif
</div>

With these changes, when you update the select values via JavaScript, Livewire will be notified and will update its internal state accordingly, ensuring that the dependent dropdowns work as expected.

dmcconnell68's avatar

I made the AI suggested code changes above, but it still not working. In dev tools, I'm getting a http 500 on POST http://localhost/livewire/update.

Laravel is throwing a TypeError, Only arrays and Traversables can be unpacked

Thoughts?

dmcconnell68's avatar

I believe I resolved the issue with this:

 Livewire.dispatch('applicationUpdated', {application: x.input_data.application});
 Livewire.dispatch('permissionSetUpdated', {permissionSet: x.input_data.permission_set});

Please or to participate in this conversation.