Debug School

rakesh kumar
rakesh kumar

Posted on • Updated on

Different way to manage data updates and UI reactivity in livewire

First Methods:
In front side/client side

<span id="totalSumAllRecords" style="float: right;">
<span wire:model="totalSum"                                           x-text="{{ $sumGst == 0 ? 'amount' : $totalSum }}">
</span> <span x-show="selectedCurrency !== ''" x-text="selectedCurrency"></span>
   </span>
Enter fullscreen mode Exit fullscreen mode

full code of client side

 <div wire:loading.class="loading" wire:target="updateCurrency">
                                <center>
                                    <div wire:loading wire:target="updateCurrency" style="text-align: center;">
                                        <img src="https://cdn.pixabay.com/animation/2023/08/11/21/18/21-18-05-265_512.gif"
                                            alt="Loading..." width="50" height="50" />
                                        <!-- Use an appropriate spinner gif -->
                                    </div>
                                </center>
                                <p>Amounting (<span x-text="items.length"></span> items):
                                    <span id="totalSumAllRecords" style="float: right;">
                                        <span wire:model="totalSum"
                                            x-text="{{ $sumGst == 0 ? 'amount' : $totalSum }}"></span> <span
                                            x-show="selectedCurrency !== ''" x-text="selectedCurrency"></span>
                                    </span>
                                </p>
                                <p>GST:
                                    <span x-text="{{ $gst == 0 ? 'calculateGST().toFixed(2)' : $gst }}"
                                        style="float: right;"></span>
                                </p>
                                <p>Total (including GST):
                                    <span x-text="{{ $sumGst == 0 ? 'calculateTotal().toFixed(2)' : $sumGst }}"
                                        style="float: right;"></span> <span x-show="selectedCurrency !== ''"
                                        x-text="selectedCurrency"></span>
                                </p>
                            </div>
Enter fullscreen mode Exit fullscreen mode

server side code

  public $totalSum = 0;
    public $gst = 0;
    public $gstRate = 18;
    public $sumGst = 0;
Enter fullscreen mode Exit fullscreen mode
   public function fetchAndPopulate()
    {
        $sum = 0;
        $gstRate = 18;
        $data_curr = [];
        log::info("yeh log info hain");
        log::info($this->item);
        if($this->item)
        {
        $this->cartIds = collect($this->item)->pluck('cart_id')->unique()->values()->all();
        log::info($this->cartIds);
        $cartDetails = AddCart::whereIn('cart_id', $this->cartIds)->get(['cart_socials', 'currency']);
        Log::info($cartDetails->toArray());
        }

            foreach ($cartDetails as $item) {             
                $socials = json_decode($item['cart_socials'], true);
                foreach ($socials as $platform => $price) {
                    $value = $price;
                }
                $currencies = $item['currency'];
                Log::info('$this->selectedCurrency: ' .$this->selectedCurrency);
            Log::info('value: ' .$value);
            Log::info('Currencies: ' . $currencies);
            $response = Http::get("https://api.currencyapi.com/v3/latest", [
                'apikey' => 'cur_live_tybhSYsNrnnxzfGe7cXpU2XKdws5h1vLH1rFKHZW',
                'base_currency' => $currencies,
                'target_currency' => $this->selectedCurrency,
            ]);
            Log::info('Prices: ok come');
            $rJson = $response->json();
            foreach ($rJson["data"] as $key => $data) {
                if ($data["code"] === $this->selectedCurrency) {
                    $roundedValue = round($data["value"] * $value);
                    $sum += $roundedValue;
                    $data_curr[] = [$data["code"] => $roundedValue];
                }
            }
            }
        $this->totalSum = $sum;
        $this->gst = floor($sum * ($gstRate / 100));
        $this->sumGst = $sum + $this->gst;
        Log::info($this->sumGst);
        Log::info($this->gst);
        Log::info($this->totalSum);
        $this->dispatch('updatedValues', $this->totalSum, $this->gst, $this->sumGst);

    }
Enter fullscreen mode Exit fullscreen mode

before updation

Image description

At the time of updation

Image description

after updation

Image description

SECOND WAY

server side code

Laravel Livewire
Trigger a Re-render After a Data Update:
Livewire components automatically re-render when their state changes. If you're updating data in a Livewire component and want the view to reflect these updates, simply modify the properties bound to the view, and Livewire will handle the re-rendering. For example:

class SomeComponent extends Component
{
    public $data;

    public function saveData()
    {
        $this->data = 'New Data';
    }

    public function render()
    {
        return view('livewire.some-component');
    }
}
Enter fullscreen mode Exit fullscreen mode

In this case, calling saveData from the Livewire component's view (like with a button click) will update $data and automatically cause the component to re-render.

Manual Trigger:
If you need to force a re-render under specific conditions or after asynchronous operations, you can use $this->dispatch to dispatch an event and listen on the same page to refresh the component.

// In your Livewire component
$this->dispatch('dataUpdated');

// In your blade file
<livewire:some-component>
<script>
    Livewire.on('dataUpdated', () => {
        Livewire.dispatch('refreshComponent');
    });
</script>
Enter fullscreen mode Exit fullscreen mode

example

<script>
    document.addEventListener('livewire:load', function () {
        Livewire.on('refreshComponent', function () {
            Livewire.dispatch('refresh');
        });
        Livewire.on('updatedSearchTerm', function () {
            console.log("updatedSearchTerm event triggered");
        });
        Livewire.on('re-render', function () {
            console.log("Component re-rendered");
        });        

    });
</script>
Enter fullscreen mode Exit fullscreen mode

in server side after save

 public function store()
        {
            log::info('Post Created Successfully.');
            $validatedDate = $this->validate([
                'title' => 'required',
                'body' => 'required',
            ]);
            Post::create($validatedDate); 
            $this->fetchPosts();// for automatic refresh
            session()->flash('message', 'Post Created Successfully.');
            $this->resetInputFields();
            // return redirect('/');
        // without refresh or reload update database data
            $this->dispatch('refreshComponent');// without refresh or reload

        }
Enter fullscreen mode Exit fullscreen mode

SECOND WAY

In server side code

public function fetchAndPopulate()
{
 $this->totalSum = $sum;
        $this->gst = floor($sum * ($gstRate / 100));
        $this->sumGst = $sum + $this->gst;
        Log::info($this->sumGst);
        Log::info($this->gst);
        Log::info($this->totalSum);
        $this->dispatch('updatedValues', $this->totalSum, $this->gst, $this->sumGst);
}
Enter fullscreen mode Exit fullscreen mode

In client side code


<script>
    document.addEventListener('livewire:load', function () {
        Livewire.on('refreshComponent', function () {
            Livewire.dispatch('refresh');
        });

        Livewire.on('updatedSearchTerm', function () {
            console.log("updatedSearchTerm event triggered");
        });

        Livewire.on('re-render', function () {
            console.log("Component re-rendered");
        });

        Livewire.on('updatedValues', function (totalSum, gst, sumGst) {
            console.log("Updated Values:", { totalSum, gst, sumGst });

            // Update the DOM elements
            document.getElementById('totalSumAllRecords').querySelector('span').innerText = totalSum;
            // Update other elements for gst and sumGst if needed
        });
    });
</script>
Enter fullscreen mode Exit fullscreen mode
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<div>
    <div class="summary-block"></div>

    <center style="margin-bottom:10px;"><b>Order Information</b></center>
    <h7>Amounting (<span id="itemCount"></span> items):
        <span id="totalSumAllRecords" style="float: right;">
            <span id="totalSum" style="float: right;"></span>
        </span>
    </h7>
    <br>
    <h7>GST: <span id="gst" style="float: right;"></span></h7>
    <br>
    <h7>Total (including GST): <span id="sumGst" style="float: right;"></span></h7>
</div>

<script>
    document.addEventListener('livewire:load', function () {
        Livewire.on('updatedValues', function (totalSum, gst, sumGst) {
            console.log("Updated Values:", { totalSum, gst, sumGst });

            // Use jQuery to update the DOM elements
            $('#totalSum').text(totalSum);
            $('#gst').text(gst.toFixed(2));
            $('#sumGst').text(sumGst.toFixed(2));
        });
    });
</script>
Enter fullscreen mode Exit fullscreen mode

================or====================

<div x-data="orderInfo()">
    <div class="summary-block"></div>

    <center style="margin-bottom:10px;"><b>Order Information</b></center>
    <h7>Amounting (<span x-text="items.length"></span> items):
        <span id="totalSumAllRecords" style="float: right;">
            <span x-text="totalSum" style="float: right;"></span>
        </span>
    </h7>
    <br>
    <h7>GST: <span x-text="gst.toFixed(2)" style="float: right;"></span></h7>
    <br>
    <h7>Total (including GST): <span x-text="sumGst.toFixed(2)" style="float: right;"></span></h7>
</div>

<script>
    function orderInfo() {
        return {
            items: [], // Initialize with empty array or appropriate data
            totalSum: 0,
            gst: 0,
            sumGst: 0,
            calculateGST() {
                return this.gst;
            },
            calculateTotal() {
                return this.sumGst;
            }
        };
    }

    document.addEventListener('livewire:load', function () {
        Livewire.on('updatedValues', function (totalSum, gst, sumGst) {
            console.log("Updated Values:", { totalSum, gst, sumGst });

            // Access the Alpine.js component and update values
            const orderInfoComponent = document.querySelector('[x-data]').__x.$data;
            orderInfoComponent.totalSum = totalSum;
            orderInfoComponent.gst = gst;
            orderInfoComponent.sumGst = sumGst;
        });
    });
</script>

Enter fullscreen mode Exit fullscreen mode

====================or===================

<div x-data="{
    cartsearch: null,
    totalSum: {!! json_encode($totalSum) !!},
    gst: {!! json_encode($gst) !!},
    sumGst: {!! json_encode($sumGst) !!}
}">
    <div class="summary-block"></div>

    <center style="margin-bottom:10px;"><b>Order Information</b></center>
    <h7>Amounting (<span x-text="items ? items.length : 0"></span> items):
        <span id="totalSumAllRecords" style="float: right;">
            <span x-text="totalSum" style="float: right;"></span>
        </span>
    </h7>
    <br>
    <h7>GST: <span x-text="gst.toFixed(2)" style="float: right;"></span></h7>
    <br>
    <h7>Total (including GST): <span x-text="sumGst.toFixed(2)" style="float: right;"></span></h7>
</div>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<script>
    document.addEventListener('livewire:load', function () {
        Livewire.on('updatedValues', function (totalSum, gst, sumGst) {
            console.log("Updated Values:", { totalSum, gst, sumGst });

            // Update the Alpine.js properties using jQuery
            $('[x-data]').each(function () {
                this.__x.$data.totalSum = totalSum;
                this.__x.$data.gst = gst;
                this.__x.$data.sumGst = sumGst;
            });

            // Use jQuery to update the DOM elements if needed
            $('#totalSum').text(totalSum);
            $('#gst').text(gst.toFixed(2));
            $('#sumGst').text(sumGst.toFixed(2));
        });
    });
</script>
Enter fullscreen mode Exit fullscreen mode

Alpine.js is designed to be reactive. When using Alpine.js in tandem with Livewire:

Update Alpine.js State from Livewire:
You can manipulate Alpine.js state (x-data) directly from Livewire by emitting a browser event and catching it in your Alpine component.

<!-- Alpine.js Component -->
<div x-data="{ open: false }">
    <button @click="open = !open">Toggle</button>
    <div x-show="open">Content</div>
</div>

<!-- Livewire Component -->
<button wire:click="someMethod">Update from Livewire</button>

<script>
    document.addEventListener('livewire:load', function () {
        window.livewire.on('updateAlpine', () => {
            Alpine.store('someStore').open = true; // if using Alpine.store
        });
    });
</script>
Enter fullscreen mode Exit fullscreen mode

Refresh Data:
You can refresh Alpine.js state when data changes in Livewire by using x-init to listen for Livewire events.

<div x-data="{ data: @entangle('data') }" x-init="@this.on('dataUpdated', () => { data = 'new data'; })">
    Current Data: <span x-text="data"></span>
</div>
Enter fullscreen mode Exit fullscreen mode

Example

namespace App\Http\Livewire;

use Livewire\Component;
use Log;
use App\Models\Post; // Assuming you have a Post model

class PostToggle extends Component
{
    public $posts;

    public function mount($posts)
    {
        $this->posts = $posts;
    }

    public function toggleAllSites($selectAll, $postId, $sites)
    {
        Log::info("toggleAllSites called with postId: $postId");
        Log::info($sites);

        // Example action: toggling a 'selected' property in the database
        $post = Post::find($postId);
        if ($post) {
            $post->selected = $selectAll;
            $post->save();
        }

        // Refetch or update posts after change
        $this->posts = Post::all(); // Or any other logic to fetch/update posts

        // Emit an event to refresh the component
        $this->dispatch('postsUpdated');
    }

    public function render()
    {
        return view('livewire.post-toggle', ['posts' => $this->posts]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Blade View (HTML + Alpine.js)

<div>
    <div x-data="{ selectedSites: [] }">
        @foreach ($posts as $post)
            <div class="card" style="padding: 27px;">
                <input type="checkbox" @change="selectedSites.push($event.target.value); $wire.toggleAllSites($event.target.checked, {{ $post->id }}, selectedSites)">
                <label>{{ $post->title }}</label>
            </div>
        @endforeach
    </div>

    <!-- This part listens for the 'postsUpdated' event and could react accordingly -->
    <div x-data="{ data: 'Initial data' }" x-init="@this.on('postsUpdated', () => { data = 'Posts have been updated'; })">
        Current Data: <span x-text="data"></span>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode
protected $listeners = ['postsUpdated' => 'fetchpost'];

   public function fetchpost()
      {
        $login_email = Auth::user()->email;
    log::info("start data state is coming1");  
    if (!empty($this->selectedfilterCity)) {
        log::info("start data selectedfilterCity is coming");

    }  
    elseif (!empty($this->selectefilterdState)) {
        log::info("here data state is coming2");
        log::info($this->selectefilterdState);

    }   
    elseif (!empty($this->selectedfilterCountry) && empty($this->selectedfilterState) && empty($this->selectedfilterCity)) {
        log::info("here data is coming3");     
        log::info($this->selectedfilterCountry);



     }
    else if ($this->selectedTags) {
        log::info("selectedTagsselectedTags srach data1");
        $posts=Country::all();
        $this->posts = $posts;
        log::info($this->posts);
    }    
    else {

        log::info("getting srach data");

        $posts=DB::connection('payments')->table("social_url")
        ->leftJoin('countries', 'social_url.country_id', '=', 'countries.country_id')
        ->leftJoin('states', 'social_url.state_id', '=', 'states.state_id')       
        ->leftJoin('cities', 'social_url.city_id', '=', 'cities.city_id')       
        ->where('social_url.user_email', '<>', $login_email)
        ->whereNotNull('social_url.social_price')
        ->select('social_url.user_id',
            DB::raw('MAX(social_url.id) as max_id'),
            'social_url.id',
            'social_url.user_name',
            'social_url.user_email',
            'social_url.slug_id',
            'social_url.slug',
            'social_url.country_id',
            'social_url.state_id',
            'social_url.city_id',
            'social_url.mobile',
            'social_url.digital_marketer',
            'social_url.bio',
            'social_url.social_site',
            'social_url.social_price',
            'social_url.social_currency', 
            'countries.country_name',
            'states.state_name',
            'cities.city_name'
        )
        ->groupBy('social_url.user_id')
        ->orderBy('max_id', 'desc')
        ->get();
        log::info("mydata");
        foreach ($posts as $key => $value) {
            $user_id = $value->user_id;
            $posts[$key]->file_pic = $profiles[$user_id] ?? null;
        }
        $this->posts = $posts;


    }

}
Enter fullscreen mode Exit fullscreen mode

These examples illustrate how to manage interactivity and reactivity between Livewire and Alpine.js efficiently. The key is using Livewire's reactivity to update the backend data and Alpine's reactivity to update the frontend without needing to manually manipulate the DOM.

Using livewire

Reference

Image description

Image description

Image description

Image description

Using alpine js
Reference

Image description

Image description

Reference

Top comments (0)