Special Offer – WordPress Website

Development Laravel

Optimizing and Extending the Livewire Product Filter – Part 4

blank

Welcome to the fourth and final part of our Livewire series! Now that we’ve built the basic product filtering system and added functional filters, we’ll optimize the product filter for performance and usability. We’ll add features like pagination, loading indicators, and animations to create a polished, user-friendly experience.

Part 3: Enhancing the Livewire Product Filter: Advanced Features

What We’ll Cover

  • Implementing pagination for better performance.
  • Optimizing Eloquent queries for filtering products.
  • Implementing loading indicators for better feedback.
  • Debouncing user inputs to reduce unnecessary updates.

Adding Pagination

For applications with many products, pagination is essential. Livewire makes it easy to add pagination with minimal configuration.

Update the Component Class

Modify the ProductFilter class to use pagination. Add the WithPagination trait:

<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\WithPagination; // Import the trait
use App\Models\Product;

class ProductFilter extends Component {
    use WithPagination; // Use the trait

    public $category = '';
    public $availability = '';
    public $minPrice = 0;
    public $maxPrice = 10000;

    public function clearFilters() {
        $this->category = '';
        $this->availability = '';
        $this->minPrice = 0;
        $this->maxPrice = 10000;
    }

    public function render() {
        $products = Product::query()
            ->when($this->category, function ($query) {
                $query->where('category', $this->category);
            })
            ->when($this->availability, function ($query) {
                $query->where('available', $this->availability === 'available');
            })
            ->when($this->minPrice, function ($query) {
                $query->where('price', '>=', $this->minPrice);
            })
            ->when($this->maxPrice, function ($query) {
                $query->where('price', '<=', $this->maxPrice);
            })
            ->paginate(9); // Paginate results

        return view('livewire.product-filter', ['products' => $products]);
    }

    public function updating($property) {
        $this->resetPage(); // Reset to page 1 when a filter is updated
    }
}

The WithPagination trait handles pagination logic. The resetPage() method ensures the component resets to the first page when filters are updated.

Update the Blade Template

Add the pagination controls to the product-filter.blade.php file:

<div>
    <!-- Filters (same as before) -->

    <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
        @foreach ($products as $product)
            <div class="bg-gray-100 border rounded p-4 text-center">
                <h3 class="font-bold">{{ $product->name }}</h3>
                <p>Category: {{ $product->category }}</p>
                <p>Price: ${{ number_format($product->price, 2) }}</p>
                <p>Status: {{ $product->available ? 'Available' : 'Unavailable' }}</p>
            </div>
        @endforeach
    </div>

    <!-- Pagination Controls -->
    <div class="mt-6">
        {{ $products->links() }} <!-- Display pagination links -->
    </div>
</div>

blank

Livewire integrates seamlessly with Laravel’s pagination system, so the links() method automatically generates the controls.

Implementing Loading Indicators

To give users feedback while the products are loading, Livewire provides a built-in wire:loading directive. Add a loading indicator to the template:

<div wire:loading wire:target="category, availability, minPrice, maxPrice"
    class="text-center text-blue-500 font-semibold">
    Loading products...
</div>

blank

The wire:loading directive shows the text only when the specified properties are being updated. You can customize the message or replace it with a spinner or animation.

Optimizing Eloquent Queries

Efficient queries are the backbone of a performant application. Let’s revisit the ProductFilter component and ensure our queries are optimized for performance.

Update the Component Logic

Modify the render method in the ProductFilter class to include optimized query logic:

<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\WithPagination;
use App\Models\Product;

class ProductFilter extends Component
{
    use WithPagination;

    public $category = '';
    public $availability = '';
    public $minPrice = 0;
    public $maxPrice = 10000;

    public function clearFilters()
    {
        $this->category = '';
        $this->availability = '';
        $this->minPrice = 0;
        $this->maxPrice = 10000;
    }

    public function render()
    {
        // Fetch filtered products with optimized queries
        $products = Product::query()
            ->when($this->category, fn ($query) => $query->where('category', $this->category))
            ->when($this->availability, fn ($query) => $query->where('available', $this->availability === 'available'))
            ->when($this->minPrice, fn ($query) => $query->where('price', '>=', $this->minPrice))
            ->when($this->maxPrice, fn ($query) => $query->where('price', '<=', $this->maxPrice))
            ->orderBy('created_at', 'desc') // Sort results for consistency
            ->paginate(9); // Limit results per page

        return view('livewire.product-filter', compact('products'));
    }

    public function updating($property)
    {
        $this->resetPage(); // Reset to page 1 when a filter is updated
    }
}

This method uses conditional clauses with when() to dynamically apply filters only when necessary. The paginate() method ensures that the query retrieves a manageable number of products per page.

Debouncing User Inputs

Livewire processes updates immediately when a user types in a field. For fields like minPrice and maxPrice, this can lead to excessive database queries. Use the debounce modifier to delay updates until the user pauses typing:

<input type="number" wire:model.change.debounce.500ms.number="minPrice" placeholder="Min Price" class="border rounded p-2 w-24" />
<input type="number" wire:model.change.debounce.500ms.number="maxPrice" placeholder="Max Price" class="border rounded p-2 w-24" />

blank

This delays updates by 500 milliseconds, reducing unnecessary queries.

Testing the Performance

To test the performance optimizations:

  • Populate the database with a large number of products.
  • Navigate to the /products page.
  • Test each filter option and ensure the results are fast and accurate.
  • Verify that pagination works seamlessly and updates the results dynamically.

For even more insights, you can use Laravel Debugbar to profile your application and ensure minimal queries are executed per request.

Conclusion

Congratulations! You’ve optimized the Livewire product filter with efficient queries, pagination, and input debouncing. These enhancements improve performance and user experience, making your application more responsive and user-friendly.

Feel free to share your progress or ask questions in the comments below.

Chat on WhatsApp Chat on WhatsApp To top