Search code examples
phplaravellaravel-livewire

Add and Substract values based on checkbox in php


I have a simple checkbox form which has three options. I want to calculate the price dynamically and i am not storing these values in a database.

<div class="custom-control custom-checkbox">
   <input type="checkbox"id="option1" wire:click="test" wire:model="additions" value="option1">
   <label class="custom-control-label" for="option1">Option 1</label>
</div>
<div class="custom-control custom-checkbox">
   <input type="checkbox" id="option2" wire:click="test" wire:model="additions" value="option2">
   <label class="custom-control-label" for="option1">Option 2</label>
</div>
<div class="custom-control custom-checkbox">
   <input type="checkbox" id="option3" wire:click="test" wire:model="additions" value="option3">
   <label class="custom-control-label" for="option1">Option 3</label>
</div>

output in the blade file where i show the value

{{ $checkout }}

Each option has different prices and i am adding to the $checkout to calculate the total.

public $additions = [];
public $checkout = 0;

public function test()
{
    // if (in_array('option1', $this->additions)) {
    //     $this->checkout =+ 10;
    //     Log::info($this->checkout);
    // }
    // if (in_array('option2', $this->additions)) {
    //    $this->checkout += 10;
    //     Log::info($this->checkout);
    // }
    // if (in_array('option3', $this->additions)) {
    //     $this->checkout += 10;
    //     Log::info($this->checkout);
    // }

    if (!empty($this->additions)) {
        foreach ($this->additions as $key => $value) {
            if ($value == 'option1') {
                $this->checkout += 10;
            }

            if ($value == 'option2') {
                $this->checkout += 10;
            } else {
                $this->checkout -= 10;
            }
            
            if ($value == 'option3') {
                $this->checkout += 10;
            } else {
                $this->checkout -= 10;
            }        
        }
        Log::info($this->checkout);
    }
}

the prices adds but is not correct. For the example i have 10 for each option so when all three options are checked, the total would be 30 and when two options are checked 20 and so on. What i am getting is all over 60 which is no where near 30.

Any help would be appreaciated.

Edited : $this->additions consists all the checked items. eg: if all three options are selected, $this->additions will have option1,option2,option3 in the array.


Solution

  • First off, your Blade view should only have one root element, so you should wrap the entire thing in a <div> tag. This is a Livewire thing, and its rather important as it makes it easier for Livewire to do its DOM-diffing.
    Secondly, you don't need both wire:click and wire:model, as you can use wire:model alone and listen to updates to the bound field through the updated() lifecycle hook - or specifically listen for the additions property through updatedAdditions().

    Then, when you perform your action, you should be resetting the counter for each iteration and avoid subtracting - otherwise, you will increment the checkout-counter for each click - which is partially what you're seeing now.

    The better alternative here is to use a lookup-array that contains the values of each option, and aggregate on that.

    <div>
        <div class="custom-control custom-checkbox">
            <input type="checkbox" class="custom-control-input" id="option1" wire:model="additions" value="option1">
            <label class="custom-control-label" for="option1">Option 1</label>
        </div>
        <div class="custom-control custom-checkbox">
            <input type="checkbox" class="custom-control-input" id="option2" wire:model="additions" value="option2">
            <label class="custom-control-label" for="option1">Option 2</label>
        </div>
        <div class="custom-control custom-checkbox">
            <input type="checkbox" class="custom-control-input" id="option3" wire:model="additions" value="option3">
            <label class="custom-control-label" for="option1">Option 3</label>
        </div>
    
        {{ $checkout }}
    </div>
    
    class Checkout extends Component
    {
        public $additions = [];
        public $checkout = 0;
    
        public function updatedAdditions($value)
        {
            // Declare valid options and the value they increment
            $optionValues = [
                'option1' => 10,
                'option2' => 10,
                'option3' => 10,
            ];
    
            // Reset the counter before we iterate over the current additions
            $this->checkout = 0;
    
            // Iterate over additions, and find the value from $validOptions
            // If it doesn't exist in $validOptions, default to 0 (adding 0 makes no difference)
            foreach ($this->additions as $key => $value) {
                $this->checkout += $optionValues[$value] ?? 0;
            }
        }
    
        public function render()
        {
            return view('livewire.checkout');
        }
    }