skip to Main Content

I’m struggling with a simple livewire component. It’s a button that adds or removes ids from an array (and also to the session). After adding a modal should appear with the different attributes.

The other components are not updating when the toggle method is called, same for the modal.

Loop:

@foreach ($listings as $listing)
    <h1>{{$listing->title}}</h1>
    <livewire:compare-listings :listing="$listing"/>
@endforeach

CompareListings.php

namespace AppLivewire;

use AppModelsListing;
use LivewireAttributesSession;
use LivewireComponent;

class CompareListings extends Component {

    public Listing $listing;

    #[Session]
    public array $comparisonList = []; // List of IDs

    public function toggleComparison($id): void {

        if (!in_array($id, $this->comparisonList)) {
            // Add ID
            $this->comparisonList[] = $id;
        } elseif (($key = array_search($id, $this->comparisonList)) !== false) {
            // Remove ID
            unset($this->comparisonList[$key]);
            // Sort array
            $this->comparisonList = array_values($this->comparisonList);
        }

    }
    public function render() {
        return view('livewire.compare-listings', [
            'listings' => Listing::whereIn('id', $this->comparisonList)->get()
        ]);
    }
    
}

compare-listings.blade.php

<div>

    <button data-modal-target="compareModal" data-modal-toggle="compareModal"
            class="mt-4 bg-gray-700 text-white px-4 py-2 rounded">
        {{ __('Show comparison list') }}
    </button>

    <button wire:click="toggleComparison({{ $listing->id }})">
        {{ __('Add/Remove comparison list') }}
    </button>

    @php
        var_dump($comparisonList);
    @endphp

    {{--    <!-- Modal -->--}}
    @push('modals')
        <div id="compareModal" tabindex="-1">
            Comparison Table
        </div>
    @endpush

2

Answers


  1. Chosen as BEST ANSWER

    I had to place a dispatch event that calls a method to update the component. It`s not very performant so I think about refactoring it via JavaScript.

    Solution:

    At the end of the method toggleComparison()

    $this->dispatch('listUpdated', $this->comparisonList);
    

    Add a new method

    #[On('listUpdated')]
    public function refreshListStatus(): void {
        $this->comparisonList = session()->get('compareListings', []);
    }
    

    This solves the problem.


  2. The question is not entirely clear, however from what I see, you are not assigning a unique key to the component included in the loop. This can cause incorrect synchronization between the rendered view and the view already displayed

    @foreach ($listings as $listing)
    
        ....
    
        <livewire:compare-listings :listing="$listing" :key="$listing->id" />
    
    @endforeach
    

    In this way the compare-listings view receives a unique key (the record id) and is updated correctly. Here you can find the related documentation.

    An additional tip
    You can avoid traversing the $comparisonList array twice when deleting an element (the first time with in_array, the second time with array_search) by simply refactoring the toggleComparison() method like this:

    function toggleComparison($id) 
    {
        if (($index = array_search($id, $this->comparisonList)) !== false) {
            array_splice($this->comparisonList, $index, 1);
        }
        else {
            $this->comparisonList[] = $id;
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search