2
votes

I previously had this:

<div wire:loading wire:target="date_range"></div>

where date_range was defined by wire:model in the same livewire component on a select element.

Because of my app structure, I now update the date_range value on a select element through AlpineJS like so, and this is done outside of the livewire component:

x-model="date_range" x-on:change="window.livewire.emit('dateRangeChanged', date_range)"

I then use an event listener in my Livewire component. This all works as expected, but the problem now is that I want to show the loading state of the element mentioned before, only when the date_range value is being updated through the global JS event. Is this possible?

The only hacky way I could come up with is that the listener method in the livewire component does something like $this->date_range_is_loading = true and set it to false at the end of the render method but that doesn’t feel right.

1

1 Answers

1
votes

If this was Vue.js you could do exactly that, i.e. set a loading property to true before beginning a long-running task and switching it back to false after it was done. Unfortunately, since Livewire runs on the server, everything is synchronous, so by the time the request comes back the task will already be complete.

What I ended up doing was reaching for Alpine.js again. Add the following to the root of your Alpine component:

x-data="{ date_range_is_loading: false }"
x-init="
    const alpine = this;
    document.addEventListener('livewire:load', () => {
        window.livewire.on('dateRangeChanged', () => alpine.date_range_is_loading = true);
    });
"

If you want to listen for Livewire dispatching an action, you can add a listener for the messageSent hook.

window.livewire.hook('messageSent', (_, message) => message.actionQueue.forEach(a => {
    if (a.type == 'callMethod' && a.payload.method == 'myAction') {
        alpine.date_range_is_loading = true; // Or whatever you need to do
    }
}))