Search code examples
laravellaravel-bladelaravel-livewire

How to populate Livewire internal state changes to outer level


My Blade view for Livewire component:

<div>
    <input type="checkbox" class="form-checkbox" wire:model="inner_checked" wire:click="toggleChecked">
    @if ($inner_checked)
        inner checked
    @else
        inner unchecked
    @endif
</div>

Works good - printed exactly according to checkbox state.

Then use this component at outer level:

<livewire:form-checkbox :id="$id" :checked=$outer_checked />
@if ($outer_checked)
    Outer checked
@else
    Outer unchecked
@endif

Works bad - outer state printed well according to initial value of $outer_checked, but changes inside checkbox not populated to outside.

Ok, rewrite mount(string $id, bool $outer_checked) to just mount(string $id) and rewrite usage of checkbox component to <livewire:form-checkbox :id="$id" wire:model=$outer_checked />. Still no changes - internal state changed, outer - not. Guess it's because wire:model not working here, at outer level.

How to populate internal state changes to outer level?


Solution

  • You'd need to use an event, dispatching it from the child (inner) and listening for it on the parent (outer)

    use Livewire\Attributes\On;
    
    class OuterComponent
    {
        public bool $outer_checked;
    
    
        #[On('inner-state-updated')]
        public function applyChangesToOuterState(bool $value)
        {
            $this->outer_checked = $value;
        }
    }
    
    class InnerComponent
    {
        public bool $inner_checked;
    
        public function updated($property)
        {
            if ($property === 'inner_checked') {
                $this->dispatch('inner-state-updated', value: $this->inner_checked);
            }
        }
    
        // alternatively
        public function updatedInnerChecked()
        {
            $this->dispatch('inner-state-updated', value: $this->inner_checked);
        }
    }
    

    Alternatively, if you can hook into this change from the javascript side, you could access the parent's property and set it there with $parent.