Search code examples
laravel-livewirealpine.js

Unable to call Livewire component method in Alpine.js: Public method [__v_raw] not found on component: [component-name]


I'm working with a combination of Laravel Livewire and Alpine.js. I encountered a peculiar issue when trying to call a Livewire component method from within an Alpine.js component.

When I obtain a Livewire component instance in Alpine.js, and then try to call one of its methods, I get the following error:

//inside alpine data object declaration.
let componentId = this.$refs.tabContent.querySelector('[wire\\:id]').getAttribute('wire:id');
this.activeTabComponent = Livewire.find(componentId);
this.activeTabComponent.call(action.method);

Public method [__v_raw] not found on component: [component-name]

Is there something wrong in my code, and/or is there any workaround?

I was trying to call a method from the topmost livewire component inside my current tab. I provide an array of actions to each tab, and I intended to call that method in the associated component. To make it clearer, this is a declaration example:

<livewire:tab-component
        title="Datos personales"
        :data="[
            'licensedProfessional' => $licensedProfessional,    
        ]"
        :tabs="[
            [
                'view' => 'admin.licensed_professionals.personal.general', 
                'label' => 'Datos generales', 
                'actions' => [
                    ['label' => 'Guardar', 'action' => 'submit']
                ]
            ],
            [
                'label' => 'Datos autorizados', 
                'component' => [
                    'name' => '\App\Http\Livewire\LicensedProfessionals\PublicProfileForm',
                ],
                'actions' => [
                    ['label' => 'Copiar de datos generales', 'action' => 'copy'],
                    ['label' => 'Guardar', 'action' => 'submit']
                ]
            ],
            ['view' => 'admin.licensed_professionals.authorization', 'label' => 'Personas autorizadas'],
            ['view' => 'admin.licensed_professionals.business_data', 'label' => 'Empresa'],
            ['view' => 'admin.licensed_professionals.signature', 'label' => 'Firma']
        ]"
    >
    </livewire:tab-component>

Solution

  • The problem here happens when you assign the component to an alpine data object.

    //This won´t work
    this.activeTabComponent = Livewire.find(componentId);
    this.activeTabComponent.call('methodName'); 
    
    //This will work
    let activeTabComponent = Livewire.find(componentId);
    activeTabComponent.call('methodName'); 
    

    This behavior is likely due to the way Alpine.js's reactivity system works. Alpine.js uses proxies to make data properties reactive, adding an extra layer of abstraction. When you assign a value to a data property, that value is "wrapped" in a proxy to monitor its changes, and probably this is what is interfering.

    When you assign the Livewire component to a local variable, it´s not wrapped in a proxy, and probably this is the reason you can use the component "as expected".

    Without digging deeper into layers of abstraction, is difficult to find the root cause, but, luckily, the solution is simple. If you are going to use complex objects, don´t assign them directly to the alpine data object, as they will get wrapped into proxies, leading to potential unexpected results.