rubendn's avatar

Using wire:confirm depending on value

I have a button that decreases the quantity in a shopping cart. If the quantity is at 1 and the user clicks the MINUS button, I want a confirmation to pop up. It is currently working as intended with the following code (I've removed CSS/SVG to make it easier to read):

<button 
wire:click="updateQuantity({{$cartContent->item_id}},'decrease')" 
@if($cartContent->quantity == 1) wire:confirm="Remove from cart?" @endif
>
MINUS
</button>

The issue I'm running into is that if a user increases the quantity to 2 or higher and then tries to decrease, the wire:confirm is firing even though the quantity is > 1.

When I inspect the code in Chrome, the wire:confirm is being removed when the quantity > 1 but it still fires when going to a quantity > 1. I only want the wire:confirm to fire if the quantity is at 1 and hitting the MINUS would remove it from the cart completely.

Any ideas what I should look at?

0 likes
3 replies
LaryAI's avatar
Level 58

It seems like you're encountering an issue where the wire:confirm directive is not updating reactively as the quantity changes. This could be due to Livewire's DOM-diffing not picking up the change in the attribute conditionally.

One way to handle this is to move the confirmation logic into your Livewire component's method. Instead of using wire:confirm in the blade template, you can check the quantity in the updateQuantity method and use JavaScript to prompt the user for confirmation when necessary.

Here's how you could adjust your Livewire component:

public function updateQuantity($itemId, $operation)
{
    $cartContent = $this->getCartContentByItemId($itemId); // Assuming you have a method to get the cart content

    if ($operation === 'decrease' && $cartContent->quantity == 1) {
        $this->confirmRemoval($itemId);
    } else {
        // Your existing logic to update the quantity
        $this->adjustQuantity($itemId, $operation);
    }
}

public function confirmRemoval($itemId)
{
    $this->dispatchBrowserEvent('confirm-removal', ['itemId' => $itemId]);
}

And in your blade template, you would listen for the confirm-removal event and show a confirmation dialog using JavaScript:

<button 
    wire:click="updateQuantity({{ $cartContent->item_id }},'decrease')"
>
    MINUS
</button>

<script>
    document.addEventListener('DOMContentLoaded', () => {
        window.addEventListener('confirm-removal', event => {
            if (confirm('Remove from cart?')) {
                @this.call('adjustQuantity', event.detail.itemId, 'decrease');
            }
        });
    });
</script>

In this solution, when the quantity is 1 and the user clicks the MINUS button, the updateQuantity method dispatches a browser event that triggers a confirmation dialog. If the user confirms, it then calls another method adjustQuantity to actually decrease the quantity.

Make sure to replace adjustQuantity with the actual method you use to update the quantity in your cart, and ensure that getCartContentByItemId is a method that retrieves the cart content by item ID.

This approach ensures that the confirmation logic is handled by the component and is always in sync with the current state of the cart content.

rubendn's avatar

This AI reply is pretty amazing and will try if someone doesn't recommend an easier fix. I figured it was some type of DOM-diffing issue even though the wire:confirm is removed from the source in the browser.

Is using Alpine an option also?

rubendn's avatar

Looks like I was able to fix the dom-diffing issue by adding a wire:key to the button using a timestamp as below...

wire:key="{{now()->timestamp}}{{$cartContent->item_id}}"
1 like

Please or to participate in this conversation.