In this lesson, we will implement the last feature for the table, column sorting.
As with everything in Livewire, first, we need will add public properties to the component.
app/Livewire/ProductsList.php:
class ProductsList extends Component{ use WithPagination; public array $categories = []; public array $countries = []; public string $sortColumn = 'products.name'; public string $sortDirection = 'asc'; public array $searchColumns = [ 'name' => '', 'price' => ['', ''], 'description' => '', 'category_id' => 0, 'country_id' => 0, // ...}
Here we also set the default column for sorting and direction. Next, we need to set the order in the query.
app/Livewire/ProductsList.php:
class ProductsList extends Component{ // ... public function render(): View { $products = Product::query() ->select(['products.*', 'countries.id as countryId', 'countries.name as countryName',]) ->join('countries', 'countries.id', '=', 'products.country_id') ->with('categories'); foreach ($this->searchColumns as $column => $value) { if (!empty($value)) { $products->when($column == 'price', function ($products) use ($value) { if (is_numeric($value[0])) { $products->where('products.price', '>=', $value[0] * 100); } if (is_numeric($value[1])) { $products->where('products.price', '<=', $value[1] * 100); } }) ->when($column == 'category_id', fn($products) => $products->whereRelation('categories', 'id', $value)) ->when($column == 'country_id', fn($products) => $products->whereRelation('country', 'id', $value)) ->when($column == 'name', fn($products) => $products->where('products.' . $column, 'LIKE', '%' . $value . '%')); } } $products->orderBy($this->sortColumn, $this->sortDirection); return view('livewire.products-list', [ 'products' => $products->paginate(10) ]); }}
Now if you visit the products page, the table will be ordered by name in ascending order.
Next, let's add buttons to the frontend. When pressed it will call the sortByColumn()
method in the Livewire component, which will accept the column name. Replace the first row in the table head with the code below:
resources/views/livewire/products-list.blade.php:
<tr> <th class="px-6 py-3 text-left bg-gray-50"> </th> <th wire:click="sortByColumn('products.name')" class="px-6 py-3 text-left bg-gray-50"> <span class="text-xs font-medium tracking-wider leading-4 text-gray-500 uppercase">Name</span> @if ($sortColumn == 'products.name') @include('svg.sort-' . $sortDirection) @else @include('svg.sort') @endif </th> <th class="px-6 py-3 text-left bg-gray-50"> <span class="text-xs font-medium tracking-wider leading-4 text-gray-500 uppercase">Categories</span> </th> <th wire:click="sortByColumn('countryName')" class="px-6 py-3 text-left bg-gray-50"> <span class="text-xs font-medium tracking-wider leading-4 text-gray-500 uppercase">Country</span> @if ($sortColumn == 'countryName') @include('svg.sort-' . $sortDirection) @else @include('svg.sort') @endif </th> <th wire:click="sortByColumn('price')" class="px-6 py-3 w-32 text-left bg-gray-50"> <span class="text-xs font-medium tracking-wider leading-4 text-gray-500 uppercase">Price</span> @if ($sortColumn == 'price') @include('svg.sort-' . $sortDirection) @else @include('svg.sort') @endif </th> <th class="px-6 py-3 text-left bg-gray-50"> </th></tr>
The svg files can be found here.
And the function, which will change column and direction:
app/Livewire/ProductsList.php:
class ProductsList extends Component{ // ... public function sortByColumn(string $column): void { if ($this->sortColumn == $column) { $this->sortDirection = $this->sortDirection == 'asc' ? 'desc' : 'asc'; } else { $this->reset('sortDirection'); $this->sortColumn = $column; } } // ...}
The last thing we will add here is Livewire functionality URL Query Parameter. It's very easy and will allow you to go through pages without resetting sorting. Also, this will allow you to refresh the page without losing sorting.
app/Http/Livewire/ProductsList.php:
use Livewire\Attributes\Url; class ProductsList extends Component{ // ... #[Url] public string $sortColumn = 'products.name'; #[Url] public string $sortDirection = 'asc'; // ...}