marinarusalka's avatar

using wire:loading to enable and disable a button

I'm using Laravel with Livewire 4, and I've built a form that has some input fields and two buttons. One button lets the user upload a file:

<button type="submit" class="btn btn-sm btn-success">Upload file</button>

And another lets them save some metadata describing the file. However, because the uploaded files have the potential to be quite large and take a while to load, I want this second button to be disabled until the file upload finishes. I attempted to code it like this:

<button wire:click="saveMetadata" class="btn btn-disabled" wire:loading.class.remove="btn btn-disabled">Save Metadata</button>

but while the file uploads successfully, the saveMetadata button remains disabled afterwards. Is there something else I need to be doing?

0 likes
2 replies
Makrid87's avatar

I think the issue is that wire:loading.class.remove is doing the opposite of what you want here.

This:

wire:loading.class.remove="btn btn-disabled"

removes those classes only while Livewire is loading, then adds them back once the request is finished. So your button ends up disabled again after the upload completes.

Instead, start with the button enabled and only disable it while the upload is in progress:

<input type="file" wire:model="file">

<button type="submit" class="btn btn-sm btn-success">
    Upload file
</button>

<button
    type="button"
    wire:click="saveMetadata"
    class="btn btn-sm btn-primary"
    wire:loading.attr="disabled"
    wire:loading.class="btn-disabled"
    wire:target="file"
>
    Save Metadata
</button>

The important parts are:

wire:loading.attr="disabled"
wire:target="file"

wire:loading.attr="disabled" actually disables the button during loading, while wire:target="file" makes sure the loading state is tied specifically to the file upload property.

Also, if this button is inside a form, I’d explicitly set type="button" on the metadata button so it doesn’t accidentally submit the form.

One more note: if your upload button calls a Livewire method instead of relying directly on wire:model, you can target that method instead:

<button
    type="button"
    wire:click="saveMetadata"
    class="btn btn-sm btn-primary"
    wire:loading.attr="disabled"
    wire:loading.class="btn-disabled"
    wire:target="uploadFile"
>
    Save Metadata
</button>

So the general idea is: use wire:loading.attr="disabled" to disable the button during the upload, and use wire:target to make sure the loading state is only tied to the upload, not to every Livewire request.

marinarusalka's avatar

Ah, thank you. I hadn't realized that wire:loading only changed the class temporarily while loading. Your explanation makes a lot of sense.

It still left me with a problem, because I wanted the metadata button to start off disabled and only become enabled after a file was uploaded. After some thought, I got around the problem by adding an $uploaded variable to my component:

public $uploaded = false;

and replaced the wire:loading in my button code with a conditional class:

class="{{ $uploaded ? 'btn btn-sm btn-success': 'btn btn-sm btn-disabled' }}"

Then I set $uploaded = true after the file upload completes. This seems to be working correctly now, though I don't know if there's a better way to do it.

Please or to participate in this conversation.